469,569 Members | 1,503 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 469,569 developers. It's quick & easy.

K&R 2 exercise 2-3

Hi~ i've studied C for a few months myself,

and i'd appreciate it if anyone could improve my coding or correct it.

the following is my solution to the K&R exercise 2-3

"Write the function htoi(s), which converts a string of hexademical digits
(including an optional 0x or 0X) into its equivalent integer value.
The allowable digits are 0 through 9, a through f, and A throught F."
//************************************************** ************************

#include <stdio.h>

int isxdigit2(int c)
{
if ( (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') || (c >= '0' && c <= '9') )
return 1;
else
return 0;
}

int tolower2(int c)
{
if (c >= 'A' && c <= 'Z')
return c+32;
else
return c;
}

int power2(int base, int num)
{
int sum;
for (sum = 1; num >0 ; num --)
sum *= base;
return sum;
}

int char_to_num(int c)
{
if (c >= '0' && c <= '9')
{
return c - 48;
}
else
{
return 10 + (tolower2(c) - 'a');
}
}

int htoi(char *c)
{
int i, k, prefix = 0;
size_t sum = 0;

if (c[0] == '0' && tolower2(c[1]) == 'x')
prefix = 1;

for (i = (prefix == 1)? 2:0 ; c[i] ;i++ )
{
if (!isxdigit2(c[i]) )
{
printf("Wrong hexa number\n");
return 0;
}
c[i] = char_to_num(c[i]);
}

for (k = (prefix == 1)? 2 : 0 ; k <= i-1 ; ++k )
{
sum += c[k] * power2(16, i-1-k);
}

return sum;
}

int main()
{
char c[] = "0xAB";
printf("%u", htoi(c));

return 0;
}

//************************************************** ****************

when i change char c[] to char *c in main(),
it shows error, why ??

Thanks..
Nov 14 '05 #1
46 3194
"Herrcho" <he*********@kornet.net> wrote in message
news:76*************************@posting.google.co m...
Hi~ i've studied C for a few months myself,
Good for you.
and i'd appreciate it if anyone could improve my coding or correct it.

the following is my solution to the K&R exercise 2-3
Excellent, finally someone who has actually shown some code! ;-)
Beware, many of my comments below are nits, but it is nice to learn the
good habits now before you'd need to unlearn the wrong ones, like myself.
"Write the function htoi(s), which converts a string of hexademical digits
(including an optional 0x or 0X) into its equivalent integer value.
The allowable digits are 0 through 9, a through f, and A throught F."

//************************************************** ************************
#include <stdio.h>

int isxdigit2(int c)
Identifiers starting with 'is' followed by a lowercase letter are reserved
by the C standard. Use something like is_xdigit2 instead.
By the way, there already is a macro isxdigit, you need to #include
<ctype.h>
{
if ( (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') || (c >= '0' && c <= '9') )

This is not guaranteed to work on non-ASCII systems. The ranges 'a'..'f' and
'A'..'F' do not need to be consecutive. It is guaranteed about '0'..'9',
though.
return 1;
else
return 0;
}
Proper indentation would make your code easier to read.
int tolower2(int c)
{
if (c >= 'A' && c <= 'Z')
return c+32;
else
return c;
}
Same comments as above. BTW, identifiers starting with 'to' are reserved
too.
int power2(int base, int num)
{
int sum;
for (sum = 1; num >0 ; num --)
sum *= base;
return sum;
}

int char_to_num(int c)
{
if (c >= '0' && c <= '9')
{
return c - 48;
Where does the magic number 48 come from? ITYM return c - '0';
}
else
{
return 10 + (tolower2(c) - 'a');
Again, this only works if you are sure that 'a'..'f' is a consecutive set.
}
}

int htoi(char *c)
{
int i, k, prefix = 0;
size_t sum = 0;

if (c[0] == '0' && tolower2(c[1]) == 'x')
prefix = 1;
Are you sure that you have 2 valid characters in c? What happens when you
call htoi("7"), for example?
Try:

if (c[0] && c[0] == '0' && c[1] && (c[1] == 'x' || c[1] == 'X'))
prefix = 1;

It's admittably a bit less elegant but safer. By the way, you could work on
an algorithm without the variable prefix. It's really simple, think about it
a little. All you need is to skip the first 2 characters of c...
for (i = (prefix == 1)? 2:0 ; c[i] ;i++ )
{
if (!isxdigit2(c[i]) )
{
printf("Wrong hexa number\n");
"Hexa" as in "jinxed"? ;-)
return 0;
}
c[i] = char_to_num(c[i]);
}

for (k = (prefix == 1)? 2 : 0 ; k <= i-1 ; ++k )
{
sum += c[k] * power2(16, i-1-k);
}

return sum;
}

int main()
{
char c[] = "0xAB";
printf("%u", htoi(c));
Err, no sir. %u in printf() expects unsigned int, but you provide it with
the result of htoi(), which returns int. This is strictly speaking an
undefined behaviour, although admittably I have yet to see a platform where
it does not work. In any case, use %d instead or change your htoi() to
return unsigned int.
return 0;
}
It looks OK, though overly complicated. You could use already available
macros isxdigit and tolower (both defined in ctype.h), but frankly you
should not even need them. And you certainly should not need your power2().

Think about it. What's 1986 in decimal?
In your algorithm, it's 1*10^3 + 9*10^2 + 8*10^1 + 1*10^0.
How about (((1)*10 + 9)*10 + 8)*10 + 6?

Now try converting it to a C program, for any (hexa)decimal number with any
number of digits.
//************************************************** ****************

when i change char c[] to char *c in main(),
it shows error, why ??
Undefined behaviour. Your htoi() tries to alter the string it is given in
situ. With char c[] in main, the string literal "0xAB" get copied to a local
array c, which is OK. But when you declare c as char *, you pass a pointer
to the string literal to htoi()... oops!
Thanks..


HTH,

Peter
Nov 14 '05 #2
nrk
Herrcho wrote:
Hi~ i've studied C for a few months myself,

and i'd appreciate it if anyone could improve my coding or correct it.

the following is my solution to the K&R exercise 2-3

"Write the function htoi(s), which converts a string of hexademical digits
(including an optional 0x or 0X) into its equivalent integer value.
The allowable digits are 0 through 9, a through f, and A throught F."


First off, not a bad attempt. But the biggest problem is that you've
assumed ASCII character set. Read on for the complete review...
//************************************************** ************************
#include <stdio.h>

#include <string.h> /* 'coz I am gonna use strchr */
int isxdigit2(int c)
{
if ( (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') || (c >= '0'
&& c <= '9') )
Here you assume 'a'-'f' and 'A'-'F' are in contiguous ascending order in the
character set. This need not be true (yes, even I wasn't happy to know
that). Note however that '0'-'9' are guaranteed to be in contiguous
ascending order by the standard.

So, what do we do? Simple, we keep a string with valid hex-alphabets and
see if the character to be checked occurs within that string:

static const char *hexalpha = "abcdefABCDEF";

if ( (c >= '0' && c <= '9') || (c && strchr(hexalpha, c)) )
return 1;
else
return 0;
}

Alternately, you could just use the isxdigit standard function, but that's
way less fun :-)
int tolower2(int c)
{
if (c >= 'A' && c <= 'Z')
return c+32;
Ouch!! Once again, you've not only assumed that 'A'-'Z' are contiguous
ascending, but also assumed that 'A'+32 == 'a', which need not be true at
all. You could either use the standard tolower, or:
static const char *uppercase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
static const char *lowercase = "abcdefghijklmnopqrstuvwxyz";

char *cptr = strchr(uppercase, c);
if ( cptr ) return lowercase[cptr - uppercase];
return c;
else
return c;
}

int power2(int base, int num)
{
int sum;
for (sum = 1; num >0 ; num --)
sum *= base;
return sum;
}

Hmmm... way too complicated... see below for why this isn't needed.
int char_to_num(int c)
{
if (c >= '0' && c <= '9')
{
return c - 48;
Ouch!! Here you assumed '0' == 48, which need not be true. Why not:
return c - '0';
}
else
{
return 10 + (tolower2(c) - 'a');
Again, 'a'-'f' need not be contiguous ascending in the character set. What
you can do instead is:
static const char *hexalpha = "abcdef";
return 10 + (strchr(hexalpha, tolower2(c)) - hexalpha);
}
}

int htoi(char *c)
Make that:
unsigned int htoi(char *c)
{
int i, k, prefix = 0;
size_t sum = 0; unsigned int sum;
if (c[0] == '0' && tolower2(c[1]) == 'x')
prefix = 1;

for (i = (prefix == 1)? 2:0 ; c[i] ;i++ )
{
if (!isxdigit2(c[i]) )
{
printf("Wrong hexa number\n");
return 0;
}
c[i] = char_to_num(c[i]);
}

for (k = (prefix == 1)? 2 : 0 ; k <= i-1 ; ++k )
{
sum += c[k] * power2(16, i-1-k);
}

return sum;
}

You can simplify matters quite a bit if you recognize that proceeding
left-to-right in the string is the best thing that you can do. Simply
multiply whatever you have by 16 and add the next number in line, and voila
you have the correct conversion at the end.

if ( c[0] == '0' && (c[1] == 'x' || c[1] == 'X') )
c += 2;
while ( *c && isxdigit2(*c) ) {
sum = (sum * 16) + char_to_num(*c);
++c;
}
if ( *c ) {
fprintf(stderr, "Invalid hex digit %c in string\n", *c);
sum = 0;
}
return sum;
int main()
{
char c[] = "0xAB";
printf("%u", htoi(c));

return 0;
}

//************************************************** ****************

when i change char c[] to char *c in main(),
it shows error, why ??

Who shows what error?

-nrk.
Thanks..


--
Remove devnull for email
Nov 14 '05 #3
nrk
Peter Pichler wrote:
"Herrcho" <he*********@kornet.net> wrote in message
news:76*************************@posting.google.co m...
Hi~ i've studied C for a few months myself,
Good for you.
and i'd appreciate it if anyone could improve my coding or correct it.

the following is my solution to the K&R exercise 2-3


Excellent, finally someone who has actually shown some code! ;-)
Beware, many of my comments below are nits, but it is nice to learn the
good habits now before you'd need to unlearn the wrong ones, like myself.
"Write the function htoi(s), which converts a string of hexademical
digits (including an optional 0x or 0X) into its equivalent integer
value. The allowable digits are 0 through 9, a through f, and A throught
F."

//************************************************** ************************

#include <stdio.h>

int isxdigit2(int c)


Identifiers starting with 'is' followed by a lowercase letter are reserved
by the C standard. Use something like is_xdigit2 instead.
By the way, there already is a macro isxdigit, you need to #include
<ctype.h>
{
if ( (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') || (c >= '0' && c
<=

'9') )

This is not guaranteed to work on non-ASCII systems. The ranges 'a'..'f'
and 'A'..'F' do not need to be consecutive. It is guaranteed about
'0'..'9', though.
return 1;
else
return 0;
}


Proper indentation would make your code easier to read.


The indentation's ok, but he/she used tabs instead of spaces. To OP: You
should use spaces to indent code that you post on the usenet.
int tolower2(int c)
{
if (c >= 'A' && c <= 'Z')
return c+32;
else
return c;
}


Same comments as above. BTW, identifiers starting with 'to' are reserved
too.
int power2(int base, int num)
{
int sum;
for (sum = 1; num >0 ; num --)
sum *= base;
return sum;
}

int char_to_num(int c)
{
if (c >= '0' && c <= '9')
{
return c - 48;


Where does the magic number 48 come from? ITYM return c - '0';
}
else
{
return 10 + (tolower2(c) - 'a');


Again, this only works if you are sure that 'a'..'f' is a consecutive set.
}
}

int htoi(char *c)
{
int i, k, prefix = 0;
size_t sum = 0;

if (c[0] == '0' && tolower2(c[1]) == 'x')
prefix = 1;


Are you sure that you have 2 valid characters in c? What happens when you
call htoi("7"), for example?


Any non-empty string will have valid values in c[0] and c[1]. Also, the
standard guarantees that '\0' != '0' :-)
Try:

if (c[0] && c[0] == '0' && c[1] && (c[1] == 'x' || c[1] == 'X'))
prefix = 1;

It's admittably a bit less elegant but safer. By the way, you could work
on an algorithm without the variable prefix. It's really simple, think
about it a little. All you need is to skip the first 2 characters of c...
for (i = (prefix == 1)? 2:0 ; c[i] ;i++ )
{
if (!isxdigit2(c[i]) )
{
printf("Wrong hexa number\n");


"Hexa" as in "jinxed"? ;-)
return 0;
}
c[i] = char_to_num(c[i]);
}

for (k = (prefix == 1)? 2 : 0 ; k <= i-1 ; ++k )
{
sum += c[k] * power2(16, i-1-k);
}

return sum;
}

int main()
{
char c[] = "0xAB";
printf("%u", htoi(c));


Err, no sir. %u in printf() expects unsigned int, but you provide it with
the result of htoi(), which returns int. This is strictly speaking an
undefined behaviour, although admittably I have yet to see a platform
where it does not work. In any case, use %d instead or change your htoi()
to return unsigned int.
return 0;
}


It looks OK, though overly complicated. You could use already available
macros isxdigit and tolower (both defined in ctype.h), but frankly you
should not even need them. And you certainly should not need your
power2().

Think about it. What's 1986 in decimal?
In your algorithm, it's 1*10^3 + 9*10^2 + 8*10^1 + 1*10^0.
How about (((1)*10 + 9)*10 + 8)*10 + 6?

Now try converting it to a C program, for any (hexa)decimal number with
any number of digits.
//************************************************** ****************

when i change char c[] to char *c in main(),
it shows error, why ??


Undefined behaviour. Your htoi() tries to alter the string it is given in
situ. With char c[] in main, the string literal "0xAB" get copied to a
local array c, which is OK. But when you declare c as char *, you pass a
pointer to the string literal to htoi()... oops!


Waah... I missed that one, didn't I? Tricksy little hobbitses...

-nrk.
Thanks..


HTH,

Peter


--
Remove devnull for email
Nov 14 '05 #4
How about this one?
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <math.h>
#include <string.h>

#define MAX_STR 80

void
reverse ( char * str )
{
char *beg, *end;

beg = str;
end = str + strlen ( str ) - 1;

while ( beg < end )
{
*beg ^= *end ^= *beg ^= *end;
beg++;
end--;
}
return;
}

int
to_num ( char dig )
{
if ( !isxdigit ( dig ) )
{
fprintf ( stderr, "Not a hexadecimal number" );
exit ( EXIT_FAILURE );
}

if ( isalpha ( dig ) )
return tolower ( dig ) - 'a' + 10;
else
return dig - '0';
}
int
main ( void )
{
char str[MAX_STR];
long dec = 0, exp = 0;
char *ptr;

printf ( "Enter a hexadecimal number: " ); if ( !fgets ( str, MAX_STR,
stdin ) ) return EXIT_FAILURE; /* discard "0x" or "0X" */
if ( str[0] == '0' )
if ( tolower ( str[1] ) == 'x' )
memmove ( str, str+2, 3 );
puts ( str );

/* use function reverse(s) of exercise 1-19.c */
reverse ( str );
ptr = str;

while ( *ptr )
{
dec = dec + to_num ( *ptr ) * pow ( 16, exp );
exp++;
ptr++;
}

printf ( "Decimal: %ld\n", dec );
return EXIT_SUCCESS;
}
Nov 14 '05 #5
"nrk" <ra*********@devnull.verizon.net> wrote:
Peter Pichler wrote:
"Herrcho" <he*********@kornet.net> wrote:

int htoi(char *c)
{
int i, k, prefix = 0;
size_t sum = 0;

if (c[0] == '0' && tolower2(c[1]) == 'x')
prefix = 1;


Are you sure that you have 2 valid characters in c? What happens when you call htoi("7"), for example?


Any non-empty string will have valid values in c[0] and c[1]. Also, the
standard guarantees that '\0' != '0' :-)


Err... yes, but... mumbleohbuggerhumblegrumble... OK, I concede ;-)
Nov 14 '05 #6
nrk
Vijay Kumar R Zanvar wrote:
How about this one?
Did you even care to test it once? Apart from being needlessly complicated,
reliant on a contiguous ascending alphabet character set, unnecessarily
using real arithmetic, causing gratuituous undefined behavior, it is also
hopelessly broken because fgets may leave '\n' in your buffer.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <math.h>
#include <string.h>

#define MAX_STR 80

void
reverse ( char * str )
{
char *beg, *end;

beg = str;
end = str + strlen ( str ) - 1;
Disaster waiting to happen when str == "".

while ( beg < end )
{
*beg ^= *end ^= *beg ^= *end;
beg++;
end--;
Needlessly cute. Try to use the language correctly before being "leet".
Whatever in the world is wrong with?:
*beg++ = *end--;
Do you object to it because it is more readable and demonstrably correct in
this context? Do you object to it because it is likely more efficient?
}
return;
}

int
to_num ( char dig )
{
if ( !isxdigit ( dig ) )
{
fprintf ( stderr, "Not a hexadecimal number" );
Missing '\n'.
exit ( EXIT_FAILURE );
}

if ( isalpha ( dig ) )
return tolower ( dig ) - 'a' + 10;
What if 'a' > 'b'? What if 'b' == 'a' + 3?
else
return dig - '0';
}
int
main ( void )
{
char str[MAX_STR];
long dec = 0, exp = 0;
char *ptr;

printf ( "Enter a hexadecimal number: " ); if ( !fgets ( str,
MAX_STR,
stdin ) ) return EXIT_FAILURE; /* discard "0x" or "0X" */
if ( str[0] == '0' )
if ( tolower ( str[1] ) == 'x' )
memmove ( str, str+2, 3 );
Oh Joy!! Even more undefined behavior. Who told you that str+3 and str+4
will contain something valid? If str == "0x" or str == "0x\n", you end up
touching uninitialized memory.
puts ( str );

/* use function reverse(s) of exercise 1-19.c */
reverse ( str );
ptr = str;

while ( *ptr )
{
dec = dec + to_num ( *ptr ) * pow ( 16, exp );
exp++;
ptr++;
}

printf ( "Decimal: %ld\n", dec );
return EXIT_SUCCESS;
}


Try to write unoptimised, "unleet", correct code before getting fancy. Try
to atleast test your code once before posting it [this one doesn't work for
one single valid case, except on stdin redirection and a non-standard file
with no ending newline that contains a valid hex number].

-nrk.

--
Remove devnull for email
Nov 14 '05 #7
nrk
nrk wrote:
Vijay Kumar R Zanvar wrote:
How about this one?


Did you even care to test it once? Apart from being needlessly
complicated, reliant on a contiguous ascending alphabet character set,
unnecessarily using real arithmetic, causing gratuituous undefined
behavior, it is also hopelessly broken because fgets may leave '\n' in
your buffer.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <math.h>
#include <string.h>

#define MAX_STR 80

void
reverse ( char * str )
{
char *beg, *end;

beg = str;
end = str + strlen ( str ) - 1;


Disaster waiting to happen when str == "".

while ( beg < end )
{
*beg ^= *end ^= *beg ^= *end;
beg++;
end--;


Needlessly cute. Try to use the language correctly before being "leet".
Whatever in the world is wrong with?:
*beg++ = *end--;
Do you object to it because it is more readable and demonstrably correct
in this context? Do you object to it because it is likely more efficient?


Got carried away there. You should object because it is demonstrably
incorrect :-) Obviously you need to swap the two values with a temporary
intermediary:

char temp = *beg;
*beg++ = *end;
*end-- = temp;

Taking a dose of my own medicine, I should've tested the darn thing before
posting.

Also, that memmove breaks your program for most valid inputs starting with
0x.

-nrk.
Nov 14 '05 #8
nrk wrote:

nrk wrote:
Vijay Kumar R Zanvar wrote:
How about this one?


Did you even care to test it once? Apart from being needlessly
complicated, reliant on a contiguous ascending alphabet character set,
unnecessarily using real arithmetic, causing gratuituous undefined
behavior, it is also hopelessly broken because fgets may leave '\n' in
your buffer.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <math.h>
#include <string.h>

#define MAX_STR 80

void
reverse ( char * str )
{
char *beg, *end;

beg = str;
end = str + strlen ( str ) - 1;


Disaster waiting to happen when str == "".

while ( beg < end )
{
*beg ^= *end ^= *beg ^= *end;
beg++;
end--;


Needlessly cute. Try to use the language correctly before being "leet".
Whatever in the world is wrong with?:
*beg++ = *end--;
Do you object to it because it is more readable and demonstrably correct
in this context? Do you object to it because it is likely more efficient?


Got carried away there. You should object because it is demonstrably
incorrect :-) Obviously you need to swap the two values with a temporary
intermediary:

char temp = *beg;
*beg++ = *end;
*end-- = temp;

Taking a dose of my own medicine, I should've tested the darn thing before
posting.

Also, that memmove breaks your program for most valid inputs starting with
0x.

-nrk.


Try this..

/*
Program: htol.c
Author: Joe Wright <jo********@earthlink.net>

Convert a hexadecimal char to its numeric equivalent.
Accommodate ASCII and EBCDIC. Maybe others.
*/

#include <stdio.h>

typedef unsigned char uchar;
typedef unsigned long ulong;

/*
We will examine a printing hex character and determine its bin value.
Of course the numerics will translate directly. The alphas are a
special case as both 'a' and 'A' will evaluate to 10.
Input must be int within the ranges '0'..'9', 'A'..'F' and 'a'..'f'.

Some assumptions:

That '0',,'9', 'A'..'F' and 'a'..'f' are contiguous in the set.
'0'..'9' is guaranteed but the others are not. Oh well, they are
contiguous in ASCII and EBCDIC.

*/

/* Returns a value 0..15 for hex digits or -1 on failure. */

int h2b(int h) {
int i, b = -1; /* Error code */
if ((i = h - '0') >= 0 && i < 10)
b = i;
else if ((i = h - 'a') >= 0 && i < 6)
b = i + 10;
else if ((i = h - 'A') >= 0 && i < 6)
b = i + 10;
return b;
}

ulong h2l(char *h) {
ulong l = 0;
int c;
while ((c = *h++) && (c == '0' || c == 'x' || c == 'X'))
;
if (c)
do {
l = l * 16 + h2b(c);
} while((c = *h++));
return l;
}

int main(int argc, char *argv[]) {
ulong ans = 0;
if (argc > 1)
ans = h2l(argv[1]);
printf("\t%lu\n", ans);
return 0;
}

--
Joe Wright http://www.jw-wright.com
"Everything should be made as simple as possible, but not simpler."
--- Albert Einstein ---
Nov 14 '05 #9
Joe Wright wrote:
.... snip ...
/*
We will examine a printing hex character and determine its bin value.
Of course the numerics will translate directly. The alphas are a
special case as both 'a' and 'A' will evaluate to 10.
Input must be int within the ranges '0'..'9', 'A'..'F' and 'a'..'f'.

Some assumptions:

That '0',,'9', 'A'..'F' and 'a'..'f' are contiguous in the set.
'0'..'9' is guaranteed but the others are not. Oh well, they are
contiguous in ASCII and EBCDIC.
*/

/* Returns a value 0..15 for hex digits or -1 on failure. */
int h2b(int h) {


Why make any assumptions?

/* also useful for reverse conversions */
static char[] hexchars = "0123456789abcdefABCDEF";

/* Returns a value 0..15 for hex digits or -1 on failure. */
int h2b(int h)
{
char * s;

if (NULL == (s = strchr(hexchars, h))) h = -1;
else {
h = s - hexchars;
if (h > 15) h = h - 6;
}
if (h > 15) h = -1; /* Exercise - why this */
return h;
}

--
Chuck F (cb********@yahoo.com) (cb********@worldnet.att.net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net> USE worldnet address!
Nov 14 '05 #10
In article <news:40***************@yahoo.com>
CBFalconer <cb********@worldnet.att.net> writes:
Why make any assumptions?

/* also useful for reverse conversions */
static char[] hexchars = "0123456789abcdefABCDEF";
You need to test these things before posting -- that should
be "static char hexchars[]". :-)

More seriously, it might be worth making it a readonly array,
of type "const char".

[snippage] if (h > 15) h = -1; /* Exercise - why this */


If you want to get rid of this, there is always memchr().
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (4039.22'N, 11150.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
Nov 14 '05 #11
Chris Torek wrote:

In article <news:40***************@yahoo.com>
CBFalconer <cb********@worldnet.att.net> writes:
Why make any assumptions?

/* also useful for reverse conversions */
static char[] hexchars = "0123456789abcdefABCDEF";


You need to test these things before posting -- that should
be "static char hexchars[]". :-)

More seriously, it might be worth making it a readonly array,
of type "const char".

[snippage]
if (h > 15) h = -1; /* Exercise - why this */


If you want to get rid of this, there is always memchr().


or

s = (h != '\0' ? strchr(hexchars, h) : NULL);

--
pete
Nov 14 '05 #12
CBFalconer wrote:

Joe Wright wrote:

... snip ...

/*
We will examine a printing hex character and determine its bin value.
Of course the numerics will translate directly. The alphas are a
special case as both 'a' and 'A' will evaluate to 10.
Input must be int within the ranges '0'..'9', 'A'..'F' and 'a'..'f'.

Some assumptions:

That '0',,'9', 'A'..'F' and 'a'..'f' are contiguous in the set.
'0'..'9' is guaranteed but the others are not. Oh well, they are
contiguous in ASCII and EBCDIC.
*/

/* Returns a value 0..15 for hex digits or -1 on failure. */
int h2b(int h) {


Why make any assumptions?

/* also useful for reverse conversions */
static char[] hexchars = "0123456789abcdefABCDEF";

/* Returns a value 0..15 for hex digits or -1 on failure. */
int h2b(int h)
{
char * s;

if (NULL == (s = strchr(hexchars, h))) h = -1;
else {
h = s - hexchars;
if (h > 15) h = h - 6;
}
if (h > 15) h = -1; /* Exercise - why this */
return h;
}

The string should be ..

static char hexchars[] = "0123456789abcdefABCDEF";

Exercise? There is a NUL at hexchars[22]. If h started off 0 strchr()
will find the NUL and 'h = s - hexchars' yields 22. 22 - 6 yields 16, an
error.

How'd I do coach? You got a job for me? In the Southwest if possible.
:-)
--
Joe Wright http://www.jw-wright.com
"Everything should be made as simple as possible, but not simpler."
--- Albert Einstein ---
Nov 14 '05 #13
Joe Wright wrote:
CBFalconer wrote:
Joe Wright wrote:

... snip ...

/*
We will examine a printing hex character and determine its bin value.
Of course the numerics will translate directly. The alphas are a
special case as both 'a' and 'A' will evaluate to 10.
Input must be int within the ranges '0'..'9', 'A'..'F' and 'a'..'f'.

Some assumptions:

That '0',,'9', 'A'..'F' and 'a'..'f' are contiguous in the set.
'0'..'9' is guaranteed but the others are not. Oh well, they are
contiguous in ASCII and EBCDIC.
*/

/* Returns a value 0..15 for hex digits or -1 on failure. */
int h2b(int h) {


Why make any assumptions?

/* also useful for reverse conversions */
static char[] hexchars = "0123456789abcdefABCDEF";

/* Returns a value 0..15 for hex digits or -1 on failure. */
int h2b(int h)
{
char * s;

if (NULL == (s = strchr(hexchars, h))) h = -1;
else {
h = s - hexchars;
if (h > 15) h = h - 6;
}
if (h > 15) h = -1; /* Exercise - why this */
return h;
}

The string should be ..

static char hexchars[] = "0123456789abcdefABCDEF";

Exercise? There is a NUL at hexchars[22]. If h started off 0
strchr() will find the NUL and 'h = s - hexchars' yields 22.
22 - 6 yields 16, an error.

How'd I do coach? You got a job for me? In the Southwest if
possible. :-)


You did better than I did. No. How about one for me, in the
Northeast. :-[

At any rate my point was: Don't make unnecessary assumptions, even
though they may be convenient.

--
Chuck F (cb********@yahoo.com) (cb********@worldnet.att.net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net> USE worldnet address!
Nov 14 '05 #14
CBFalconer <cb********@yahoo.com> wrote:
Joe Wright wrote:
CBFalconer wrote: <snip>
> /* also useful for reverse conversions */
> static char[] hexchars = "0123456789abcdefABCDEF";
>
> /* Returns a value 0..15 for hex digits or -1 on failure. */
> int h2b(int h)
> {
> char * s;
>
> if (NULL == (s = strchr(hexchars, h))) h = -1;
> else {
> h = s - hexchars;
> if (h > 15) h = h - 6;
> }
> if (h > 15) h = -1; /* Exercise - why this */
> return h;
> }
<snip> Exercise? There is a NUL at hexchars[22]. If h started off 0
strchr() will find the NUL and 'h = s - hexchars' yields 22.
22 - 6 yields 16, an error.

<snip>

My 2ct:

if ( h && (s = strchr( hexchars, h )) )
/*...*/

is a well-known idiom for retrieving the position of a non-null
character in a test string with strchr. Alternatively memchr
could be used, as suggested by Chris Torek elsethread.
Regards
--
Irrwahn Grausewitz (ir*******@freenet.de)
welcome to clc : http://www.ungerhu.com/jxh/clc.welcome.txt
clc faq-list : http://www.faqs.org/faqs/C-faq/faq/
acllc-c++ faq : http://www.contrib.andrew.cmu.edu/~a...FAQ-acllc.html
Nov 14 '05 #15
Hi nrk~ Thanks for your comments. really good for my learning C.

i corrected my code.. Could you check it out ?

/************************************************** ***********************
#include <stdio.h>
#include <string.h>

int lowercase(char c)
{
static const char *uppercase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
static const char *lowercase = "abcdefghijklmnopqrstuvwxyz";

char *cptr;
cptr = strchr(uppercase, c);
if ( cptr ) return lowercase[cptr - uppercase];
return c;
}

int char_to_num(char c)
{
char *k = "abcdef";

if (c >= '0' && c <= '9')
return c - '0';
else
return strchr(k, lowercase(c)) - k + 10;
}

int isxdigit2(char c)
{
static const char *hexalpha = "abcdefABCDEF";

if ( (c >= '0' && c <= '9') || (c && strchr(hexalpha, c)) )
return 1;
else
return 0;
}

unsigned htoi(char *c)
{
int sum = 0;

if ( c[0] == '0' && (c[1] == 'x' || c[1] == 'X') )
c += 2;
while (*c && isxdigit2(*c) )
{
sum = (sum * 16) + char_to_num(*c);
++c;
}
if ( *c ) {
fprintf(stdout, "Invalid hex digit %c in string\n", *c);
sum = 0;
}
return sum;
}

int main()
{
char *c = "0Xca";
printf("%u", htoi(c));

return 0;
}
/************************************************** ***************

it runs well , but i have a couple of questions..

what's the difference when i change 'stderr' to 'stdout' in the below.

fprintf(stderr, "Invalid hex digit %c in string\n", *c);

it doesn't make any difference in my machine.

and in isxdigit2 function, when i remove 'static' keyword ,

from 'static const char *hexalpha = "abcdefABCDEF"; '
to ' const char *hexalpha = "abcdefABCDEF"; '

what's the difference ? i know what static means in C, but

i don't see why 'static' needs in isxdigit2 function.
Nov 14 '05 #16
Herrcho wrote:
.... snip ...
what's the difference when i change 'stderr' to 'stdout' in the below.

fprintf(stderr, "Invalid hex digit %c in string\n", *c);
stderr and stdout are different files, but usually (not always)
connected to the 'terminal' by default. You can control the
destination for stdout in most OSs with redirection. If that is
done using stderr allows the error messages to remain visible on
the terminal.

and in isxdigit2 function, when i remove 'static' keyword ,

from 'static const char *hexalpha = "abcdefABCDEF"; '
to ' const char *hexalpha = "abcdefABCDEF"; '

what's the difference ? i know what static means in C, but
i don't see why 'static' needs in isxdigit2 function.


The first line loads hexalpha once at program startup. The second
loads it every time the function isxdigit2 is called, and
generates extra code to do so.

--
Chuck F (cb********@yahoo.com) (cb********@worldnet.att.net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net> USE worldnet address!
Nov 14 '05 #17
he*********@kornet.net (Herrcho) wrote:
<snip>
i corrected my code.. Could you check it out ?
Now that you've called for it ... ;-)
/************************************************** ***********************
#include <stdio.h>
#include <string.h>

int lowercase(char c) To be consistent with the standard library functions, I suggest
to use int for character arguments.{
static const char *uppercase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
static const char *lowercase = "abcdefghijklmnopqrstuvwxyz"; Nitpick:
static const char const *...
;-) char *cptr; Nit:
const char *cptr;
cptr = strchr(uppercase, c);
if ( cptr ) return lowercase[cptr - uppercase];
return c;
} int char_to_num(char c) See above.{
char *k = "abcdef"; Nit:
static const char const *k = "abcdef"
if (c >= '0' && c <= '9')
return c - '0';
else
return strchr(k, lowercase(c)) - k + 10;
}
And you better make sure to exclusively feed hexdigit characters
to the char_to_num function (in the call in main below you do, of
course).
int isxdigit2(char c) See above, plus: identifiers beginning with 'is' followed by a
lowercase letter are reserved for future library extensions;
is_xdigit2 would be OK, though.{
static const char *hexalpha = "abcdefABCDEF"; Nit: static const char const *...
if ( (c >= '0' && c <= '9') || (c && strchr(hexalpha, c)) )
return 1;
else
return 0;
} unsigned htoi(char *c) unsigned htoi( const char *c ){
int sum = 0; Since you are going to return the value of sum, let it match
the return type:
unsigned int sum = 0;

I would use unsigned long (or maybe even size_t) as return type,
anyway.
if ( c[0] == '0' && (c[1] == 'x' || c[1] == 'X') )
c += 2;
while (*c && isxdigit2(*c) )
{
sum = (sum * 16) + char_to_num(*c);
++c;
}
if ( *c ) {
fprintf(stdout, "Invalid hex digit %c in string\n", *c);
sum = 0; I'm not sure if altering the conversion result in this case is
the most sensible thing to do.
}
return sum;
}

int main()
{
char *c = "0Xca"; const char *c = ...
printf("%u", htoi(c));

return 0;
}
/************************************************** ***************

it runs well , I assume you didn't compile with maximum warning level... ;-)
but i have a couple of questions..
what's the difference when i change 'stderr' to 'stdout' in the below.

fprintf(stderr, "Invalid hex digit %c in string\n", *c);

it doesn't make any difference in my machine.
The stdout and stderr streams may be associated with different
files/devices.

<OT>
Imagine your program being invoked from a unixish command shell
like this:

foo 2>foo_stderr_log

</OT>

There may also be a difference in buffering, see C99 7.19.3:

7 [...] As initially opened, the standard error stream is
not fully buffered; the standard input and standard output
streams are fully buffered if and only if the stream can
be determined not to refer to an interactive device.
and in isxdigit2 function, when i remove 'static' keyword ,

from 'static const char *hexalpha = "abcdefABCDEF"; '
to ' const char *hexalpha = "abcdefABCDEF"; '

what's the difference ? i know what static means in C, but
i don't see why 'static' needs in isxdigit2 function.


The static storage-class specifier really isn't needed in this
case, but it's sensible to use it: since the pointer isn't
changed throughout program execution, one single instance of
it is sufficient for the code at hand. Thus it's logical to
declare it static at function scope and let it being initialized
during program startup, rather than creating and destroying an
automatic instance each and every time the function is called or
returns, respectively. As mentioned above, the most pedantic
declaration is:

static const char const *hexalpha = "....";

You could also drop the pointer variable completely and put
the string literal in the call to strchr, but IMHO that would
just add to obfuscation and wouldn't have any real advantages.

HTH
Regards
--
Irrwahn Grausewitz (ir*******@freenet.de)
welcome to clc : http://www.ungerhu.com/jxh/clc.welcome.txt
clc faq-list : http://www.faqs.org/faqs/C-faq/faq/
acllc-c++ faq : http://www.contrib.andrew.cmu.edu/~a...FAQ-acllc.html
Nov 14 '05 #18
nrk
Herrcho wrote:
Hi nrk~ Thanks for your comments. really good for my learning C.

i corrected my code.. Could you check it out ?

/************************************************** ***********************
#include <stdio.h>
#include <string.h>

int lowercase(char c)
{
static const char *uppercase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
static const char *lowercase = "abcdefghijklmnopqrstuvwxyz";

char *cptr;
cptr = strchr(uppercase, c);
if ( cptr ) return lowercase[cptr - uppercase];
return c;
}

int char_to_num(char c)
{
char *k = "abcdef";

static const char *hexalpha = "abcdef";

See Irrwahn and CBF's answers for why static might be a good idea. Also,
try to give meaningful names for long-lived variables such as this one.
Calling it "k" is not useful at all. Calling it hexalpha ostensibly
provides some idea of what you're trying to achieve.
if (c >= '0' && c <= '9')
return c - '0';
else
return strchr(k, lowercase(c)) - k + 10;
}
See Irrwahn's point about this function. I hit the post button in my
original reply and then thought of the issue Irrwahn brought up. It is a
good point. While in your current code, char_to_num is guaranteed to
receive only a valid lowercase hex digit, on your next cut-n-paste of this
"working" char_to_num, you may get a rather nasty surprise if that
pre-condition is not satisfied. So, here's a char_to_num that fails
gracefully:

int char_to_num(char c) {
static const char *lhexalpha = "abcdef";
char *cptr;

if ( c >= '0' && c <= '9' ) return c - '0';
else if ( c && (cptr = strchr(lhexalpha, c)) )
return 10 + cptr - hexalpha;
return -1; /* Negative return indicates failure */
}

Keep in mind that this char_to_num doesn't handle uppercase hex digits.
That's fine in the current context, but I would probably add a comment to
the function to avoid a surprise when I cut-n-paste this code somewhere
else later on.

int isxdigit2(char c)
{
static const char *hexalpha = "abcdefABCDEF";

if ( (c >= '0' && c <= '9') || (c && strchr(hexalpha, c)) )
I didn't elaborate on the (c && strchr(hexalpha, c)) part. But if you
didn't give it much thought, see CBF's post upthread with his little
"exercise" to see why this is important.
return 1;
else
return 0;
}

unsigned htoi(char *c)
{
int sum = 0;

If you're returning unsigned, why not make sum match that return?
unsigned sum = 0;
if ( c[0] == '0' && (c[1] == 'x' || c[1] == 'X') )
c += 2;
while (*c && isxdigit2(*c) )
{
sum = (sum * 16) + char_to_num(*c);
++c;
}
if ( *c ) {
fprintf(stdout, "Invalid hex digit %c in string\n", *c);
Error messages are better off in the standard error stream. I don't have my
K&R1 with me (it's thousands of miles away right now, and I definitely do
miss it. If it weren't out of my student budget, I would definitely buy
another copy :-( ), but I am sure it explains standard input (stdin),
standard output (stdout) and standard error (stderr), the three streams
that are available to you at the start of your program.
sum = 0;
}
return sum;
}

int main()
{
char *c = "0Xca";
printf("%u", htoi(c));

return 0;
}
/************************************************** ***************

it runs well , but i have a couple of questions..

what's the difference when i change 'stderr' to 'stdout' in the below.

fprintf(stderr, "Invalid hex digit %c in string\n", *c);

it doesn't make any difference in my machine.

See Irrwahn's answer. On typical systems, both stdout and stderr are tied
to your terminal by default. However, if you're on a Unixish system try
out his suggestion and view the contents of foo_stderr_log (or the file you
redirect stderr to) to see the difference between my version and yours.
and in isxdigit2 function, when i remove 'static' keyword ,

from 'static const char *hexalpha = "abcdefABCDEF"; '
to ' const char *hexalpha = "abcdefABCDEF"; '

what's the difference ? i know what static means in C, but

i don't see why 'static' needs in isxdigit2 function.


It is not needed, but is probably a good idea (excellent answers from others
tell you why, and there's nothing I can add).

-nrk.

--
Remove devnull for email
Nov 14 '05 #19
nrk
Irrwahn Grausewitz wrote:
he*********@kornet.net (Herrcho) wrote:
<snip>
i corrected my code.. Could you check it out ?


Now that you've called for it ... ;-)
/************************************************** ***********************
#include <stdio.h>
#include <string.h>

int lowercase(char c)

To be consistent with the standard library functions, I suggest
to use int for character arguments.
{
static const char *uppercase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
static const char *lowercase = "abcdefghijklmnopqrstuvwxyz";

Nitpick:
static const char const *...


Nitpick, ITYM:
static const char * const ...

Here, and in other places as well :-)

-nrk.

--
Remove devnull for email
Nov 14 '05 #20
"nrk" <ra*********@devnull.verizon.net> wrote:
Irrwahn Grausewitz wrote:
he*********@kornet.net (Herrcho) wrote:
static const char *uppercase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
static const char *lowercase = "abcdefghijklmnopqrstuvwxyz";

Nitpick:
static const char const *...


Nitpick, ITYM:
static const char * const ...

Here, and in other places as well :-)


Correct, though I would use:
static const char uppercase[] = ...
static const char lowercase[] = ...

There are two advantages:
1. Saving 2*sizeof(char*) bytes, and
2. Being able to apply sizeof to 'uppercase' and 'lowercase'.

I am not aware of any disadvantages ;-)

Peter
Nov 14 '05 #21
nrk <ra*********@devnull.verizon.net> wrote:
Irrwahn Grausewitz wrote:
he*********@kornet.net (Herrcho) wrote:
<snip>
static const char *lowercase = "abcdefghijklmnopqrstuvwxyz";

Nitpick:
static const char const *...


Nitpick, ITYM:
static const char * const ...

Here, and in other places as well :-)


Umm, yes, don't know what I was thinking.
Thanks for correction. :-)

Regards
--
Irrwahn Grausewitz (ir*******@freenet.de)
welcome to clc : http://www.ungerhu.com/jxh/clc.welcome.txt
clc faq-list : http://www.faqs.org/faqs/C-faq/faq/
acllc-c++ faq : http://www.contrib.andrew.cmu.edu/~a...FAQ-acllc.html
Nov 14 '05 #22
Martin O'Brien wrote:
/* hex2int.c: Convert hexadecimal number in any locale */
/* Source: THE STANDARD C LIBRARY by P J Plauger, p34 */
/* NOTE: This code does not check for overflow. That requires */
/* additional complexity. */

#include <ctype.h>
#include <string.h>

int hex2int(const char *s)
{
int value;
static const char xd[] =
{"0123456789abcdefABCDEF"};

static const char xv[] =
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
10, 11, 12, 13, 14, 15,
10, 11, 12, 13, 14, 15};

for (value = 0; isxdigit(*s); ++s)
value = (value << 4) + xv[strchr(xd, *s) - xd];

return value;


I believe htoi() should return an unsigned int (perhaps unsigned long).
AFAIK, you cannot portably represent signed values in hex. In any case,
Plauger's code exhibits undefined behavior, so this is definitely not
the implementation you want to use.

/david

--
Andre, a simple peasant, had only one thing on his mind as he crept
along the East wall: 'Andre, creep... Andre, creep... Andre, creep.'
-- unknown
Nov 14 '05 #23
David wrote:
I believe htoi() should return an
unsigned int (perhaps unsigned long). AFAIK,
you cannot portably represent signed values in hex.
In any case, Plauger's code exhibits undefined
behavior, so this is definitely not the
implementation you want to use.


The mistake is mine. I wrapped Plauger's code in a function definition
and wrongly put the return type as int.

Plauger says this:

---
To convert a hexadecimal number in any locale, write:

#include <ctype.h>
#include <string.h>
....
static const char xd[] =
{"0123456789abcdefABCDEF"};

static const char xv[] =
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
10, 11, 12, 13, 14, 15,
10, 11, 12, 13, 14, 15};

for (value = 0; isxdigit(*s); ++s)
value = (value << 4) + xv[strchr(xd, *s) - xd];

Note that this code does not check for overflow. That requires
additional complexity.
---

Martin
http://martinobrien.co.uk/
Nov 14 '05 #24
Martin O'Brien wrote:

David wrote:
I believe htoi() should return an
unsigned int (perhaps unsigned long). AFAIK,
you cannot portably represent signed values in hex.
In any case, Plauger's code exhibits undefined
behavior, so this is definitely not the
implementation you want to use.


The mistake is mine. I wrapped Plauger's code in a function
definition and wrongly put the return type as int.

Plauger says this:

---
To convert a hexadecimal number in any locale, write:

#include <ctype.h>
#include <string.h>
...
static const char xd[] =
{"0123456789abcdefABCDEF"};

static const char xv[] =
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
10, 11, 12, 13, 14, 15,
10, 11, 12, 13, 14, 15};

for (value = 0; isxdigit(*s); ++s)
value = (value << 4) + xv[strchr(xd, *s) - xd];

Note that this code does not check for overflow. That requires
additional complexity.


It still exhibits undefined behaviour. You need to define value.
Also s, although we can make some assumptions about that.

--
Chuck F (cb********@yahoo.com) (cb********@worldnet.att.net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net> USE worldnet address!
Nov 14 '05 #25
"CBFalconer" wrote:
It still exhibits undefined behaviour. You need to define value.
Also s, although we can make some assumptions about that.


I'm puzzled. How can it exhibit anything if it doesn't compile?

Martin

Nov 14 '05 #26
On 19 Feb 2004 00:33:08 -0800, ma************@which.net (Martin
O'Brien) wrote:
David wrote:
I believe htoi() should return an
unsigned int (perhaps unsigned long). AFAIK,
you cannot portably represent signed values in hex.
In any case, Plauger's code exhibits undefined
behavior, so this is definitely not the
implementation you want to use.


The mistake is mine. I wrapped Plauger's code in a function definition
and wrongly put the return type as int.

Plauger says this:

---
To convert a hexadecimal number in any locale, write:

#include <ctype.h>
#include <string.h>
...
static const char xd[] =
{"0123456789abcdefABCDEF"};

static const char xv[] =
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
10, 11, 12, 13, 14, 15,
10, 11, 12, 13, 14, 15};

for (value = 0; isxdigit(*s); ++s)
value = (value << 4) + xv[strchr(xd, *s) - xd];

Note that this code does not check for overflow. That requires
additional complexity.
---

Martin
http://martinobrien.co.uk/


htoi1 "check for overflow" ? Is it right?
How checking for overflow?

#include <stdio.h>
int lower(int c)
{if(c>='A' && c<='Z') return c+'a'-'A';
else return c;
}

int isdigit(int c)
{if(c>='0' && c<='9') return 1; else return 0;}

int ispace(int c)
{ if(c==' ' || c=='\t' || c=='\n') return 1; else return 0;}
int htoi1(char s[])
{unsigned i=0, n=0, d, h;
char c;

while( (c=s[i])==' ' || c=='\t' || c=='\n' )
i++;
if( c=='0' && ( s[i+1]=='x' || s[i+1]=='X') )
{i+=2; c=s[i];}
while(1)
{d= ('0'<=c && c<='9' ) ? c - '0' :
( c>='A' && c<='F' ) ? c - 'A' + 10:
( c>='a' && c<='f' ) ? c - 'a' + 10: 16;
if(d==16)
break;
if( (h=16 * n) < n || (n=h+d)<h || n<d )
{n= ((int)n)>0 ? ((~0u)>>1) : ((~0u)>>1)+1; break;}
c=s[++i];
}
return (int) n;
}
int htoi(char s[])
{int i=0,n=0;
while(ispace(s[i])) i++;
if(s[i]=='0'&& lower(s[i+1])=='x') i+=2;
for( ; ;++i)
if( isdigit(s[i]) ) n=16*n + (s[i]-'0');
else if((lower(s[i])>='a' && lower(s[i])<='f'))
n=16*n+lower(s[i])-'a'+ 10;
else break;
return n;
}

main()
{char b[30];
int c, ch, j;
do{printf("\nLista di numeri esadecinmali(1 termina)>");
do{scanf("%s", &b);
c=htoi1(b);
printf("\nPartenza=%s\n",b);
printf("Arrivo =%d\n", c);
c=htoi(b);
printf("\nPartenza=%s\n",b);
printf("Arrivo =%d\n", c);
if((ch=fgetc(stdin) )=='\n') break;
else ungetc(ch,stdin);
} while(ch!=EOF );
}while(c!=1);
return 0;
}

Nov 14 '05 #27
Hello RoRsOaMrPiEo.

Your code is very busy. Why are you writing functions lower(), isdigit() and
isspace() when the Standard Library has them? (in the C Library lower() is
called tolower()).

And this thread should have convinced you that although you can assume the
characters '0' to '9' have consecutive values, you can not make that
assumption about upper and lower case letters. Which is why Plauger uses a
table of values xv, to define the values of the characters in xd.

Also, Chuck has already said that my function wrapper around Plauger's
suggestion was faulty because it returned int, which was an oversight on my
part, and your function now does the same, and even casts the results of its
calculations (in an unsigned int) to int before returning it.

I think what Plauger means about additional complexity for overflow is to
flag a warning if overflow is indicated and stop the conversion. It's what
I'd do anyway.

--
Martin
http://martinobrien.co.uk/
"RoRsOaMrPiEo" wrote:
htoi1 "check for overflow" ? Is it right?
How checking for overflow?

#include <stdio.h> [...]
} while(ch!=EOF ); }while(c!=1);
return 0;
}


Nov 14 '05 #28
"Martin" <martin.o_brien@[no-spam]which.net> writes:
"CBFalconer" wrote:
It still exhibits undefined behaviour. You need to define value.
Also s, although we can make some assumptions about that.


I'm puzzled. How can it exhibit anything if it doesn't compile?


"Undefined behavior" means that the standard poses no requirements on
how a conforming implementation behaves. If a compiler is part of the
implementation, not compiling the code at all is therefore just as
allowed as generating executable code.

(FWIW, there are cases of undefined behavior which only occurs at
run-time for some input data. An obvious example is any program which
calls the `gets' function. In such cases, the compiler must compile the
program.)
--
,--. Martin Dickopp, Dresden, Germany ,= ,-_-. =.
/ ,- ) http://www.zero-based.org/ ((_/)o o(\_))
\ `-' `-'(. .)`-'
`-. Debian, a variant of the GNU operating system. \_/
Nov 14 '05 #29
RoRsOaMrPiEo wrote:
.... snip ...
#include <stdio.h>

int lower(int c)
{if(c>='A' && c<='Z') return c+'a'-'A';
else return c;
}


Already non-portable code, with foul formatting. I see at least
four blanks you could have saved.

--
Chuck F (cb********@yahoo.com) (cb********@worldnet.att.net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net> USE worldnet address!
Nov 14 '05 #30
On Thu, 19 Feb 2004 21:12:59 -0000, "Martin"
<martin.o_brien@[no-spam]which.net> wrote:
Hello RoRsOaMrPiEo.

Your code is very busy. Why are you writing functions lower(), isdigit() and
isspace() when the Standard Library has them? (in the C Library lower() is
called tolower()).
ok, ok
And this thread should have convinced you that although you can assume the
characters '0' to '9' have consecutive values, you can not make that
assumption about upper and lower case letters. Which is why Plauger uses a
table of values xv, to define the values of the characters in xd.
I assume ascii or ebcdic and a two's complement pc
Also, Chuck has already said that my function wrapper around Plauger's
suggestion was faulty because it returned int, which was an oversight on my
part, and your function now does the same, and even casts the results of its
calculations (in an unsigned int) to int before returning it.
Do you show some numeric examples?
I think what Plauger means about additional complexity for overflow is to
flag a warning if overflow is indicated and stop the conversion. It's what
I'd do anyway.


Nov 14 '05 #31
On Fri, 20 Feb 2004 07:05:54 GMT, RoRsOaMrPiEo <n@esiste.ee> wrote:

I assume that CHAR_MAX < 512

#include <stdio.h>
#include <assert.h>
#include <limits.h>

int htoi1(char s[])
{unsigned i=0, n=0, d, h;
char c;

assert(s!=NULL);
while( (c=s[i])==' ' || c=='\t' || c=='\n' )
i++;
if( c=='0' && ( s[i+1]=='x' || s[i+1]=='X') )
{i+=2; c=s[i];}
while(1)
{d= ('0'<=c && c<='9' ) ? c - '0' :
( c>='A' && c<='F' ) ? c - 'A' + 10:
( c>='a' && c<='f' ) ? c - 'a' + 10: 16;
if(d==16)
break;
if( (h=16 * n) < n || (n=h+d)<h || n<d )
{n= ((int)n)>0 ? ((~0u)>>1) : ((~0u)>>1)+1; break;}
c=s[++i];
}
return (int) n;
}
char* volte1(void)
{static char xd[512] = {16};
xd['0']= 0; xd['1']= 1; xd['2']= 2; xd['3']= 3;
xd['4']= 4; xd['5']= 5; xd['6']= 6; xd['7']= 7;
xd['8']= 8; xd['9']= 9;
xd['a']=10; xd['b']=11; xd['c']=12; xd['d']=13;
xd['e']=14; xd['f']=15;
xd['A']=10; xd['B']=11; xd['C']=12; xd['D']=13;
xd['E']=14; xd['F']=15;
return xd;
}
int htoi2(char* s)
{unsigned i=0, n=0, d, h;
static char *p=0;
char c;

assert(s!=NULL);
if(p==0) p=volte1();

while( (c=s[i])==' ' || c=='\t' || c=='\n' )
i++;
if( c=='0' && ( s[i+1]=='x' || s[i+1]=='X') )
{i+=2; c=s[i];}
while(1)
{d= c>0 ? p[c]: 16;
if(d==16)
break;
if( n>(UINT_MAX/16) || ( h=(n*16) )> UINT_MAX - d )
{n= ((int)n)>0 ? INT_MAX : INT_MIN; break;}
n= h + d;
c=s[++i];
}
return (int) n;
}
int main(void)
{char b[30]={0};
int c, ch, j;

assert(CHAR_MAX<=512);
do{printf("\nLista di numeri esadecinmali(1 termina)>");
do{scanf("%s", &b);
c=htoi1(b);
printf("\nPartenza=%s\n",b);
printf("Arrivo =%d\n", c);
c=htoi2(b);
printf("\nPartenza=%s\n",b);
printf("Arrivo =%d\n", c);
if((ch=fgetc(stdin) )=='\n') break;
else ungetc(ch,stdin);
} while(ch!=EOF );
}while(c!=1);
return 0;
}

Do you like it?
Nov 14 '05 #32
On Fri, 20 Feb 2004 08:44:50 GMT, RoRsOaMrPiEo <n@esiste.ee> wrote:
On Fri, 20 Feb 2004 07:05:54 GMT, RoRsOaMrPiEo <n@esiste.ee> wrote:

I assume that CHAR_MAX < 512


I assume '0'...'9','a'...'f','A'...'F' < 512
#include <stdio.h>
#include <assert.h>
#include <limits.h>

/* It is wrong ...*/
int htoi1(char s[])
{unsigned i=0, n=0, d, h;
char c;

assert(s!=NULL);
while( (c=s[i])==' ' || c=='\t' || c=='\n' )
i++;
if( c=='0' && ( s[i+1]=='x' || s[i+1]=='X') )
{i+=2; c=s[i];}
while(1)
{d= ('0'<=c && c<='9' ) ? c - '0' :
( c>='A' && c<='F' ) ? c - 'A' + 10:
( c>='a' && c<='f' ) ? c - 'a' + 10: 16;
if(d==16)
break;
if( (h=16 * n) < n || (n=h+d)<h || n<d )
{n= ((int)n)>0 ? ((~0u)>>1) : ((~0u)>>1)+1; break;}
c=s[++i];
}
return (int) n;
}
char* volte1(void)
{static char xd[512] = {16};
xd['0']= 0; xd['1']= 1; xd['2']= 2; xd['3']= 3; xd['4']= 4;
xd['5']= 5;
xd['6']= 6; xd['7']= 7; xd['8']= 8; xd['9']= 9;
xd['a']=10; xd['b']=11; xd['c']=12; xd['d']=13; xd['e']=14;
xd['f']=15;
xd['A']=10; xd['B']=11; xd['C']=12; xd['D']=13; xd['E']=14;
xd['F']=15;
return xd;
}

int ci_siamo_o_no(void)
{if('9'>= 512 ||
'a'>= 512 || 'b'>= 512 || 'c'>= 512 || 'd'>= 512 || 'e'>= 512 ||
'f'>= 512 ||
'A'>= 512 || 'B'>= 512 || 'C'>= 512 || 'D'>= 512 || 'E'>= 512 ||
'F'>= 512
) return 0;
return 1;
}

int htoi2(char* s)
{unsigned i=0, n=0, d, h;
static char *p=0;
char c;

assert(s!=NULL);
if(p==0) p=volte1();

while( (c=s[i])==' ' || c=='\t' || c=='\n' )
i++;
if( c=='0' && ( s[i+1]=='x' || s[i+1]=='X') )
{i+=2; c=s[i];}
while(1)
{d= c>0 && (unsigned) c < 512u ? p[c]: 16;
if(d==16)
break;
if( n>(UINT_MAX/16) || ( h=(n*16) )> UINT_MAX - d )
{n= ((int)n)>0 ? INT_MAX : INT_MIN; break;}
n= h + d;
c=s[++i];
}
return (int) n;
}
int main(void)
{char b[30]={0};
int c, ch, j;

c=ci_siamo_o_no();
assert(c==1);

do{printf("\nLista di numeri esadecinmali(1 termina)>");
do{scanf("%29s", &b);
c=htoi1(b);
printf("\nPartenza=%s\n",b);
printf("Arrivo =%d\n", c);
c=htoi2(b);
printf("\nPartenza=%s\n",b);
printf("Arrivo =%d\n", c);
if((ch=fgetc(stdin) )=='\n') break;
else ungetc(ch,stdin);
} while(ch!=EOF );
}while(c!=1);
return 0;
}
Nov 14 '05 #33
On Fri, 20 Feb 2004 01:41:33 GMT, CBFalconer <cb********@yahoo.com>
wrote:
RoRsOaMrPiEo wrote:

... snip ...

#include <stdio.h>

int lower(int c)
{if(c>='A' && c<='Z') return c+'a'-'A';
else return c;
}


Already non-portable code, with foul formatting. I see at least
four blanks you could have saved.


Do you say that you can make a "htoi()" better than my "htoi2()" ?
Nov 14 '05 #34
RoRsOaMrPiEo <n@esiste.ee> wrote:
On Fri, 20 Feb 2004 01:41:33 GMT, CBFalconer <cb********@yahoo.com>
wrote:
RoRsOaMrPiEo wrote:

#include <stdio.h>

int lower(int c)
{if(c>='A' && c<='Z') return c+'a'-'A';
else return c;
}


Already non-portable code, with foul formatting. I see at least
four blanks you could have saved.


Do you say that you can make a "htoi()" better than my "htoi2()" ?


Easily. Why do work which the library will do for you?

#include <limits.h>
#include <stdlib.h>

unsigned int htoi(char *txt)
{
unsigned long tmp=strtoul(txt, 0, 16);
if (tmp>UINT_MAX) return UINT_MAX;
return tmp;
}

Shorter, sweeter, doesn't waste value space on negative numbers which
you don't parse anyway, doesn't invoke undefined behaviour on overflow,
and is portable no matter what your character set it. Feel free.

Richard
Nov 14 '05 #35
On Fri, 20 Feb 2004 10:13:10 GMT, rl*@hoekstra-uitgeverij.nl (Richard
Bos) wrote:
RoRsOaMrPiEo <n@esiste.ee> wrote:
On Fri, 20 Feb 2004 01:41:33 GMT, CBFalconer <cb********@yahoo.com>
wrote:
>RoRsOaMrPiEo wrote:
>>
>> #include <stdio.h>
>>
>> int lower(int c)
>> {if(c>='A' && c<='Z') return c+'a'-'A';
>> else return c;
>> }
>
>Already non-portable code, with foul formatting. I see at least
>four blanks you could have saved.
Do you say that you can make a "htoi()" better than my "htoi2()" ?


Easily. Why do work which the library will do for you?

#include <limits.h>
#include <stdlib.h>

unsigned int htoi(char *txt)
{
unsigned long tmp=strtoul(txt, 0, 16);
if (tmp>UINT_MAX) return UINT_MAX;
return tmp;
}


but here htoi(8eeeeeeeeeeeeeeeeeeeeeee)==-1

this seems htoi(8eeeeeeeeeeeeeeeeeeeeeee)== INT_MAX

unsigned int htoi(char *txt)
{unsigned long tmp=strtoul(txt, 0, 16);
if (tmp>=UINT_MAX)
return INT_MAX;
return tmp;
}
Shorter, sweeter, doesn't waste value space on negative numbers which
you don't parse anyway, doesn't invoke undefined behaviour on overflow,
and is portable no matter what your character set it. Feel free.

Richard

but my htoi2 seems 2*faster than library htoi()

C:>2_7_c
test is ok
Differenza libreria =6.000000 s
Differenza mia =2.000000 s

C:>2_7_c
test is ok
Differenza libreria =6.000000 s
Differenza mia =3.000000 s

C:>2_7_c
test is ok
Differenza libreria =6.000000 s
Differenza mia =3.000000 s

C:>2_7_c
test is ok
Differenza libreria =6.000000 s
Differenza mia =3.000000 s

C:>2_7_c
test is ok
Differenza libreria =6.000000 s
Differenza mia =3.000000 s
#include <stdio.h>
#include <assert.h>
#include <limits.h>
#include <stdlib.h>
#include <time.h>

char* riempi_hex(char* a, int lunghezza)
{static char ary[]="0123456789abcdefABCDEF";
int i, j, lungh;

assert( a!=NULL && lunghezza>13 );
lungh = rand() % 12;
for( j=0; j<lungh; ++j )
a[j]=ary[ rand() % 21 ];

a[j]=0;
return a;
}

unsigned int htoi(char *txt)
{unsigned long tmp=strtoul(txt, 0, 16);
if (tmp>=UINT_MAX)
return INT_MAX;
return tmp;
}

char* volte1(void)
{static char xd[512] = {16};
xd['0']= 0; xd['1']= 1; xd['2']= 2; xd['3']= 3; xd['4']= 4; xd['5']=
5;
xd['6']= 6; xd['7']= 7; xd['8']= 8; xd['9']= 9;
xd['a']=10; xd['b']=11; xd['c']=12; xd['d']=13; xd['e']=14;
xd['f']=15;
xd['A']=10; xd['B']=11; xd['C']=12; xd['D']=13; xd['E']=14;
xd['F']=15;
return xd;
}

int ci_siamo_o_no(void)
{if('9'>= 512 ||
'a'>= 512 || 'b'>= 512 || 'c'>= 512 || 'd'>= 512 || 'e'>= 512 ||
'f'>= 512 ||
'A'>= 512 || 'B'>= 512 || 'C'>= 512 || 'D'>= 512 || 'E'>= 512 ||
'F'>= 512
) return 0;
return 1;
}

int htoi2(char* s)
{unsigned i=0, n=0, d, h;
static char *p=0;
char c;

assert(s!=NULL);
if(p==0) p=volte1();

while( (c=s[i])==' ' || c=='\t' || c=='\n' )
i++;
if( c=='0' && ( s[i+1]=='x' || s[i+1]=='X') )
{i+=2; c=s[i];}
while(1)
{d= c>0 && (unsigned) c < 512u ? p[c]: 16;
if(d==16)
break;
if( n>(UINT_MAX/16) || ( h=(n*16) )> UINT_MAX - d )
{n= ((int)n)>0 ? INT_MAX : INT_MIN; break;}
n= h + d;
c=s[++i];
}
return (int) n;
}
int main(void)
{char b[30]={0};
int c, ch, j;
time_t x, y;

c=ci_siamo_o_no();
assert(c==1);
srand(time(0));

for(j=0; j<700000; ++j)
{riempi_hex(b, 30);
c=htoi(b); ch=htoi2(b);
if(c!=ch && c-ch!=-1)
{printf("\nPartenza=%s\n",b);
printf("Arrivo =%d\n", c );
printf("Arrivo1 =%d\nTest fails \n", ch);
}
}

printf("test is ok \n");
x=time(0);
for(j=0; j<7000000; ++j)
{riempi_hex(b, 30);
c=htoi(b);
if(c==9999999)
{printf("\nPartenza=%s\n",b);
printf("Arrivo =%d\n", c );
}
}

y=time(0);
printf("Differenza libreria =%f s \n", difftime(y,x) );

x=time(0);
for(j=0; j<7000000; ++j)
{riempi_hex(b, 30);
c=htoi2(b);
if(c==9999999)
{printf("\nPartenza=%s\n",b);
printf("Arrivo =%d\n", c );
}
}
y=time(0);
printf("Differenza mia =%f s \n", difftime(y,x) );

return 0;
}

Nov 14 '05 #36
RoRsOaMrPiEo <n@esiste.ee> wrote:
On Fri, 20 Feb 2004 10:13:10 GMT, rl*@hoekstra-uitgeverij.nl (Richard
Bos) wrote:
RoRsOaMrPiEo <n@esiste.ee> wrote:
Do you say that you can make a "htoi()" better than my "htoi2()" ?


Easily. Why do work which the library will do for you?

#include <limits.h>
#include <stdlib.h>

unsigned int htoi(char *txt)
{
unsigned long tmp=strtoul(txt, 0, 16);
if (tmp>UINT_MAX) return UINT_MAX;
return tmp;
}


but here htoi(8eeeeeeeeeeeeeeeeeeeeeee)==-1

this seems htoi(8eeeeeeeeeeeeeeeeeeeeeee)== INT_MAX


Imprimis, htoi(8eeeeeeeeeeeeeeeeeee) is a syntax error.
Secundis, htoi("8eeeeeeeeeeeeeeeeeeee") invokes undefined behaviour for
your implementation (and thus has a license to return anything,
including garbage, and even crash the machine), and returns UINT_MAX
(not INT_MAX) for my implementation, without being undefined.
Shorter, sweeter, doesn't waste value space on negative numbers which
you don't parse anyway, doesn't invoke undefined behaviour on overflow,
and is portable no matter what your character set it. Feel free.

but my htoi2 seems 2*faster than library htoi()


There is no library htoi() (not in Standard C, at least), and some
slight slowness, while not ideal, is at least to be preferred above a
license to crash your machine at any inconvenient moment.

Richard
Nov 14 '05 #37
On Fri, 20 Feb 2004 10:18:29 GMT, RoRsOaMrPiEo <n@esiste.ee> wrote:
On Fri, 20 Feb 2004 01:41:33 GMT, CBFalconer <cb********@yahoo.com>
wrote:
RoRsOaMrPiEo wrote:

... snip ...

#include <stdio.h>

int lower(int c)
{if(c>='A' && c<='Z') return c+'a'-'A';
else return c;
}


Already non-portable code, with foul formatting. I see at least
four blanks you could have saved.


Do you say that you can make a "htoi()" better than my "htoi2()" ?


Excuse me if I gave offence to you
It would be easy if we use pointer instead of index
but

int htoi3(char* s)
{unsigned n=0, d, h;
static char *p=0;
char c;

assert(s!=NULL);
if(p==0) p=volte1();

while( (c=*s)==' ' || c=='\t' || c=='\n' )
s++;
if( c=='0' && ( s[1]=='x' || s[1]=='X') )
{s += 2; c = *s;}
while(1)
{d= c>0 && (unsigned) c < 512u ? p[c]: 16;
if(d==16)
break;
if( n>(UINT_MAX/16) || ( h=(n*16) )> UINT_MAX - d )
{n= ((int)n)>0 ? INT_MAX : INT_MIN; break;}
n= h + d;
c=*++s;
}
return (int) n;
}

seems slower of htoi2 in my sys.
Nov 14 '05 #38
On Fri, 20 Feb 2004 12:32:52 GMT, rl*@hoekstra-uitgeverij.nl (Richard
Bos) wrote:
> #include <limits.h>
> #include <stdlib.h>
>
> unsigned int htoi(char *txt)
> {
> unsigned long tmp=strtoul(txt, 0, 16);
> if (tmp>UINT_MAX) return UINT_MAX;
> return tmp;
> }
but here htoi(8eeeeeeeeeeeeeeeeeeeeeee)==-1

this seems htoi(8eeeeeeeeeeeeeeeeeeeeeee)== INT_MAX


Imprimis, htoi(8eeeeeeeeeeeeeeeeeee) is a syntax error.
Secundis, htoi("8eeeeeeeeeeeeeeeeeeee") invokes undefined behaviour for
your implementation (and thus has a license to return anything,
including garbage, and even crash the machine), and returns UINT_MAX
(not INT_MAX) for my implementation, without being undefined.


so your is htou and not htoi
>Shorter, sweeter, doesn't waste value space on negative numbers which
>you don't parse anyway, doesn't invoke undefined behaviour on overflow,
>and is portable no matter what your character set it. Feel free.

but my htoi2 seems 2*faster than library htoi()


There is no library htoi() (not in Standard C, at least),


ok, htoi that use library (strtoul(txt, 0, 16))
and some
slight slowness, while not ideal, is at least to be preferred above a
license to crash your machine at any inconvenient moment.
crash where in code?
Richard

Nov 14 '05 #39
"Richard Bos" wrote:
Why do work which the library will do for you?

#include <limits.h>
#include <stdlib.h>

unsigned int htoi(char *txt)
{
unsigned long tmp=strtoul(txt, 0, 16);
if (tmp>UINT_MAX) return UINT_MAX;
return tmp;
}

Shorter, sweeter, doesn't waste value space on
negative numbers which you don't parse anyway,
doesn't invoke undefined behaviour on overflow,
and is portable no matter what your character set it.
Feel free.


Isn't there a possibility that UINT_MAX == ULONG_MAX?

Martin
http://martinobrien.co.uk/

Nov 14 '05 #40
On Fri, 20 Feb 2004 14:12:54 GMT, RoRsOaMrPiEo <n@esiste.ee> wrote:
On Fri, 20 Feb 2004 12:32:52 GMT, rl*@hoekstra-uitgeverij.nl (Richard
Bos) wrote:
> #include <limits.h>
> #include <stdlib.h>
>
> unsigned int htoi(char *txt)
> {
> unsigned long tmp=strtoul(txt, 0, 16);
> if (tmp>UINT_MAX) return UINT_MAX;
> return tmp;
> }

but here htoi(8eeeeeeeeeeeeeeeeeeeeeee)==-1

this seems htoi(8eeeeeeeeeeeeeeeeeeeeeee)== INT_MAX


Imprimis, htoi(8eeeeeeeeeeeeeeeeeee) is a syntax error.
Secundis, htoi("8eeeeeeeeeeeeeeeeeeee") invokes undefined behaviour for
your implementation (and thus has a license to return anything,
including garbage, and even crash the machine), and returns UINT_MAX
(not INT_MAX) for my implementation, without being undefined.


so your is htou and not htoi

is there any pc where
(int) (unsigned) INT_MAX != INT_MAX (this would be true for K&R?)
or where
(int) (unsigned) INT_MIN != INT_MIN

or where if zE{INT_MIN...INT_MAX}
then (int) (unsigned) z != z
Nov 14 '05 #41
Martin wrote:
"Richard Bos" wrote:
Why do work which the library will do for you?

#include <limits.h>
#include <stdlib.h>

unsigned int htoi(char *txt)
{
unsigned long tmp=strtoul(txt, 0, 16);
if (tmp>UINT_MAX) return UINT_MAX;
return tmp;
}

Shorter, sweeter, doesn't waste value space on
negative numbers which you don't parse anyway,
doesn't invoke undefined behaviour on overflow,
and is portable no matter what your character set it.
Feel free.


Isn't there a possibility that UINT_MAX == ULONG_MAX?


So? As before, this means input >= UINT_MAX returns UINT_MAX.

--
Chuck F (cb********@yahoo.com) (cb********@worldnet.att.net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net> USE worldnet address!
Nov 14 '05 #42
"CBFalconer" wrote:
So? As before, this means input >= UINT_MAX returns UINT_MAX.


If UINT_MAX == ULONG_MAX then tmp>UINT_MAX can never be true and UINT_MAX
will never be returned by your function, even when overflow occurs.

Martin
http://martinobrien.co.uk/

Nov 14 '05 #43
Martin wrote:
"CBFalconer" wrote:
So? As before, this means input >= UINT_MAX returns UINT_MAX.


If UINT_MAX == ULONG_MAX then tmp>UINT_MAX can never be true and
UINT_MAX will never be returned by your function, even when
overflow occurs.


You snipped the code in question and the attributions (it wasn't
my function), but strtoul will return ULONG_MAX for an overflow,
IIRC, which in this case is == UINT_MAX, and is returned. The
code is portable.

I repeat - so?

--
Chuck F (cb********@yahoo.com) (cb********@worldnet.att.net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net> USE worldnet address!

Nov 14 '05 #44
nrk
Martin wrote:
"CBFalconer" wrote:
So? As before, this means input >= UINT_MAX returns UINT_MAX.
If UINT_MAX == ULONG_MAX then tmp>UINT_MAX can never be true and UINT_MAX
will never be returned by your function, even when overflow occurs.


That would automatically be taken care of by strtoul. In case of overflow,
strtoul will return ULONG_MAX (which also happens to UINT_MAX in the
scenario you describe) and set errno to ERANGE. Richard's code takes the
extra care for situations where ULONG_MAX > UINT_MAX.

-nrk.
Martin
http://martinobrien.co.uk/


--
Remove devnull for email
Nov 14 '05 #45
RoRsOaMrPiEo <n@esiste.ee> wrote:
On Fri, 20 Feb 2004 12:32:52 GMT, rl*@hoekstra-uitgeverij.nl (Richard
Bos) wrote:
> #include <limits.h>
> #include <stdlib.h>
>
> unsigned int htoi(char *txt)
> {
> unsigned long tmp=strtoul(txt, 0, 16);
> if (tmp>UINT_MAX) return UINT_MAX;
> return tmp;
> }

but here htoi(8eeeeeeeeeeeeeeeeeeeeeee)==-1

this seems htoi(8eeeeeeeeeeeeeeeeeeeeeee)== INT_MAX


Imprimis, htoi(8eeeeeeeeeeeeeeeeeee) is a syntax error.
Secundis, htoi("8eeeeeeeeeeeeeeeeeeee") invokes undefined behaviour for
your implementation (and thus has a license to return anything,
including garbage, and even crash the machine), and returns UINT_MAX
(not INT_MAX) for my implementation, without being undefined.


so your is htou and not htoi


If you wish. Yours doesn't read signed hex numbers, either, though, so I
fail to see the advantage of having a signed format. If you wish, you
can remove all unsigneds, use strtol() instead of strtoul(), and INT_MAX
instead of UINT_MAX, and you'll have a version which can read only half
of the original numbers but returns a signed int.

In fact, if I were you, I'd use strtoul() directly. Much simpler.
and some
slight slowness, while not ideal, is at least to be preferred above a
license to crash your machine at any inconvenient moment.


crash where in code?


Wherever it invokes undefined behaviour. I haven't checked it in detail,
but people upthread said that it does. They may, of course, have been
mistaken.

Richard
Nov 14 '05 #46
RoRsOaMrPiEo <n@esiste.ee> wrote:
is there any pc where
(int) (unsigned) INT_MAX != INT_MAX (this would be true for K&R?)
No. INT_MAX must be representable in unsigned int (6.2.5#9 in C99).
(int) (unsigned) INT_MIN != INT_MIN

or where if zE{INT_MIN...INT_MAX}
then (int) (unsigned) z != z


Whether such a machine actually exists I don't know, but AFAICT it's
certainly allowed. Conversion of out-of-range values to unsigned format
is defined to be done modulo (<type>_MAX+1), but conversion of out-of-
range values to signed format is not well-defined.

Richard
Nov 14 '05 #47

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

6 posts views Thread by leonard greeff | last post: by
12 posts views Thread by Chris Readle | last post: by
12 posts views Thread by Merrill & Michele | last post: by
16 posts views Thread by Josh Zenker | last post: by
19 posts views Thread by arnuld | last post: by
5 posts views Thread by arnuld | last post: by
9 posts views Thread by JFS | last post: by
88 posts views Thread by santosh | last post: by
4 posts views Thread by guiromero | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.