strtoul() behavior

A

arnuld

WANTED: To know the behavior of strtoul()
GOT: It works!
WHY POSTING: for improvements.

string contains a value which could be an int, long int or unsigned long
and I need to get that value using strtoul(). I have put error checks but
still I think I will get more advice on making it better:


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <errno.h>

int str_to_ulongint(const char* str, unsigned long int* ulp);

int main(void)
{
unsigned long i = 127; /* initialize to some value to distinguish
between default and new values */
unsigned long i2 = 128;
/* unsigned long is 10 digits at maximum as per section 5.1.1 in H&s5 */
char arrc[11] = {0};
const char* arrc2 = "12345677899686848484";

int ret = sprintf(arrc, "%lu", ULONG_MAX);
if(EOF == ret || 0 > ret)
{
printf("sprintf() error\n");
exit(EXIT_FAILURE);
}

printf("i = %lu\narrc = %s, strlen(arrc): %u\n\n", i, arrc, strlen
(arrc));
if(0 > str_to_ulongint(arrc, &i))
{
printf("error converting values\n");
exit(EXIT_FAILURE);
}
printf("i = %lu\n\n", i);

printf("i2 = %lu\narrc2 = %s, strlen(arrc2): %u\n\n", i2, arrc2,
strlen(arrc2));
if(0 > str_to_ulongint(arrc2, &i2))
{
printf("error converting values\n");
exit(EXIT_FAILURE);
}
printf("i2 = %lu\n", i2);

return 0;
}


int str_to_ulongint(const char* str, unsigned long int* ulp)
{
int ret;
unsigned long int num;
char* p;
errno = 0;

if(NULL == str || '\0' == *str)
{
printf("Invalid Args\n");
return -1;
}

p = NULL;
num = strtoul(str, &p, 10);
/* Error check as per section 16.4 of H&S 5 */
if(ERANGE == errno)
{
if((0 == num) && (0 == strcmp(str, p)))
{
printf("strtoul() could not convert string\n");
}
else if(ULONG_MAX == num)
{
printf("strtoul() overflow error\n");
}
else
{
printf("strange output from strtoul()\n");
}

perror("*ERROR*");
ret = -1;
}
else if((0 == errno) && (NULL != p && '\0' == *p))
{
printf("Successful Conversion by strtoul()\n");
*ulp = num;
ret = 1;
}
else
{
printf( "strange conversions and errno values :(\n");
printf( "num = %lu, ULONG_MAX = %lu", num, ULONG_MAX);
perror("*ERROR*");
ret = -1;
}

return ret;
}

============================= OUTPUT ===============================
[arnuld@dune programs]$ gcc -ansi -pedantic -Wall -Wextra str-to-ulong.c
[arnuld@dune programs]$ ./a.out
i = 127
arrc = 4294967295, strlen(arrc): 10

Successful Conversion by strtoul()
i = 4294967295

i2 = 128
arrc2 = 12345677899686848484, strlen(arrc2): 20

strtoul() overflow error
*ERROR*: Numerical result out of range
error converting values
[arnuld@dune programs]$
 
I

Ike Naar

WANTED: To know the behavior of strtoul()
GOT: It works!
Sorry.

[snip]
#include <limits.h>
[snip]
/* unsigned long is 10 digits at maximum as per section 5.1.1 in H&s5 */

This is not the case. You probably misunderstood the text from that paragraph.
ULONG_MAX is required to be at least 4294967295 but it can be larger.
For instance, I'm typing this sentence on a machine where ULONG_MAX equals
18446744073709551615.
char arrc[11] = {0};
[snip]
int ret = sprintf(arrc, "%lu", ULONG_MAX);

So, on this machine this statement would overflow the arrc array.
 
B

Ben Bacarisse

arnuld said:
WANTED: To know the behavior of strtoul()
GOT: It works!
WHY POSTING: for improvements.

string contains a value which could be an int, long int or unsigned long
and I need to get that value using strtoul(). I have put error checks but
still I think I will get more advice on making it better:


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <errno.h>

int str_to_ulongint(const char* str, unsigned long int* ulp);

int main(void)
{
unsigned long i = 127; /* initialize to some value to distinguish
between default and new values */
unsigned long i2 = 128;
/* unsigned long is 10 digits at maximum as per section 5.1.1 in H&s5 */

Not on my implementation.
char arrc[11] = {0};
const char* arrc2 = "12345677899686848484";

int ret = sprintf(arrc, "%lu", ULONG_MAX);
if(EOF == ret || 0 > ret)

It's almost always easier to test for what you want rather than all the
cases that are wrong. I'd test for ret != 1. Anything other than 1
means that something has gone wrong which seems to be all you want to
know.
{
printf("sprintf() error\n");
exit(EXIT_FAILURE);
}

printf("i = %lu\narrc = %s, strlen(arrc): %u\n\n", i, arrc, strlen
(arrc));

You need to cast the return from strlen to unsigned. That's what %u
expects. Alternatively use %zu from C99.
if(0 > str_to_ulongint(arrc, &i))
{
printf("error converting values\n");
exit(EXIT_FAILURE);
}
printf("i = %lu\n\n", i);

printf("i2 = %lu\narrc2 = %s, strlen(arrc2): %u\n\n", i2, arrc2,
strlen(arrc2));
Ditto.

if(0 > str_to_ulongint(arrc2, &i2))
{
printf("error converting values\n");
exit(EXIT_FAILURE);
}
printf("i2 = %lu\n", i2);

return 0;
}


int str_to_ulongint(const char* str, unsigned long int* ulp)
{
int ret;
unsigned long int num;
char* p;
errno = 0;

if(NULL == str || '\0' == *str)
{
printf("Invalid Args\n");
return -1;
}

p = NULL;
num = strtoul(str, &p, 10);

I prefer to set errno immediately before the call I am interested in.
If you change the code to add something that can set errno in the
preceding 9 lines, you might be in trouble.
/* Error check as per section 16.4 of H&S 5 */
if(ERANGE == errno)
{
if((0 == num) && (0 == strcmp(str, p)))

Why strcmp? Surely strcmp(str, p) == 0 only when str == p?
{
printf("strtoul() could not convert string\n");

I don't think you can get here. When errno == ERANGE num is never going
to be zero.
}
else if(ULONG_MAX == num)
{
printf("strtoul() overflow error\n");
}
else
{
printf("strange output from strtoul()\n");

I don't think you can get here either. Once you know that errno ==
ERANGE, all you can do is

assert(num == ULONG_MAX);

if you feel you need to catch weird non-conforming implementations.
}

perror("*ERROR*");
ret = -1;
}
else if((0 == errno) && (NULL != p && '\0' == *p))
{
printf("Successful Conversion by strtoul()\n");
*ulp = num;
ret = 1;
}
else
{
printf( "strange conversions and errno values :(\n");
printf( "num = %lu, ULONG_MAX = %lu", num, ULONG_MAX);
perror("*ERROR*");
ret = -1;

This is too common a case to call "strange". Also the perror("*ERROR*")
is going to be rather confusing. For example, I get

*ERROR*: Success

for all sorts of common errors like converting "12 " or "abc".
}

return ret;
}

============================= OUTPUT ===============================

If you make main take a command-line argument you can test all sorts of
strings very quickly.

<snip>
 
G

Georg Peter

WANTED: To know the behavior of strtoul()
GOT: It works!
WHY POSTING: for improvements. [snip]
  num = strtoul(str, &p, 10);
  /* Error check as per section 16.4 of H&S 5 */
  if(ERANGE == errno)

I don't know about section 16.4 of H&S 5, but normally
errno is used in a different way: Errno usually has
only a defined meaning when a function returns a value
which indicates an error. AFAIK errno alone cannot be
used to find out if a function has succeeded or failed.

Georg Peter
 
B

Ben Bacarisse

Georg Peter said:
WANTED: To know the behavior of strtoul()
GOT: It works!
WHY POSTING: for improvements. [snip]
  num = strtoul(str, &p, 10);
  /* Error check as per section 16.4 of H&S 5 */
  if(ERANGE == errno)

I don't know about section 16.4 of H&S 5, but normally
errno is used in a different way: Errno usually has
only a defined meaning when a function returns a value
which indicates an error. AFAIK errno alone cannot be
used to find out if a function has succeeded or failed.

That seems to be at odds with this from section 7.5:

3. The value of errno is zero at program startup, but is never set to
zero by any library function. The value of errno may be set to
nonzero by a library function call whether or not there is an error,
provided the use of errno is not documented in the description of
the function in this International Standard.

The fact that the description of strtoul does document the use of errno
means that strtoul may not set errno to nonzero other than as documented
in the function's description.

It's true that errno == ERANGE alone is not enough; you must ensure
that errno is zero before the call, but the OP's code does that.
 
K

Keith Thompson

Ben Bacarisse said:
Georg Peter said:
WANTED: To know the behavior of strtoul()
GOT: It works!
WHY POSTING: for improvements. [snip]
  num = strtoul(str, &p, 10);
  /* Error check as per section 16.4 of H&S 5 */
  if(ERANGE == errno)

I don't know about section 16.4 of H&S 5, but normally
errno is used in a different way: Errno usually has
only a defined meaning when a function returns a value
which indicates an error. AFAIK errno alone cannot be
used to find out if a function has succeeded or failed.

That seems to be at odds with this from section 7.5:

3. The value of errno is zero at program startup, but is never set to
zero by any library function. The value of errno may be set to
nonzero by a library function call whether or not there is an error,
provided the use of errno is not documented in the description of
the function in this International Standard.

The fact that the description of strtoul does document the use of errno
means that strtoul may not set errno to nonzero other than as documented
in the function's description.

It's true that errno == ERANGE alone is not enough; you must ensure
that errno is zero before the call, but the OP's code does that.

Yes, and there's nothing that can happen between setting errno
to 0 and calling strtoul() that could set errno to a non-zero value.
(There's a printf, but it's followed by a "return -1".)

But it's a good idea to set errno to 0 *immediately* preceding the call
you want to check. For example, if you add a printf statement for
debugging purposes, it could set errno to a non-zero value even if it
succeeds. (blah blah, printf vs. debugginer, blah blah)
 
B

Ben Bacarisse

Keith Thompson said:
Ben Bacarisse said:
Georg Peter said:
WANTED: To know the behavior of strtoul()
GOT: It works!
WHY POSTING: for improvements.
[snip]
  num = strtoul(str, &p, 10);
  /* Error check as per section 16.4 of H&S 5 */
  if(ERANGE == errno)

I don't know about section 16.4 of H&S 5, but normally
errno is used in a different way: Errno usually has
only a defined meaning when a function returns a value
which indicates an error. AFAIK errno alone cannot be
used to find out if a function has succeeded or failed.

That seems to be at odds with this from section 7.5:

3. The value of errno is zero at program startup, but is never set to
zero by any library function. The value of errno may be set to
nonzero by a library function call whether or not there is an error,
provided the use of errno is not documented in the description of
the function in this International Standard.

The fact that the description of strtoul does document the use of errno
means that strtoul may not set errno to nonzero other than as documented
in the function's description.

It's true that errno == ERANGE alone is not enough; you must ensure
that errno is zero before the call, but the OP's code does that.

Yes, and there's nothing that can happen between setting errno
to 0 and calling strtoul() that could set errno to a non-zero value.
(There's a printf, but it's followed by a "return -1".)

But it's a good idea to set errno to 0 *immediately* preceding the call
you want to check.

Yes. I made this point myself when originally commenting on the code.
 
B

Barry Schwarz

WANTED: To know the behavior of strtoul()
GOT: It works!
WHY POSTING: for improvements.

string contains a value which could be an int, long int or unsigned long
and I need to get that value using strtoul(). I have put error checks but
still I think I will get more advice on making it better:


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <errno.h>

int str_to_ulongint(const char* str, unsigned long int* ulp);

int main(void)
{
unsigned long i = 127; /* initialize to some value to distinguish
between default and new values */
unsigned long i2 = 128;
/* unsigned long is 10 digits at maximum as per section 5.1.1 in H&s5 */

An unwarranted assumption (regarding ULONG_MAX)
char arrc[11] = {0};
const char* arrc2 = "12345677899686848484";

int ret = sprintf(arrc, "%lu", ULONG_MAX);
if(EOF == ret || 0 > ret)

Sine EOF is guaranteed to be negative, the left operand of || is
redundant.

I wonder when sprintf can return a negative value. fprintf and printf
do so for I/O errors but that is not possible with sprintf.
{
printf("sprintf() error\n");
exit(EXIT_FAILURE);
}

printf("i = %lu\narrc = %s, strlen(arrc): %u\n\n", i, arrc, strlen
(arrc));

Another unwarranted assumption (regarding size_t).
if(0 > str_to_ulongint(arrc, &i))
{
printf("error converting values\n");
exit(EXIT_FAILURE);
}
printf("i = %lu\n\n", i);

printf("i2 = %lu\narrc2 = %s, strlen(arrc2): %u\n\n", i2, arrc2,
strlen(arrc2));
Ditto.

if(0 > str_to_ulongint(arrc2, &i2))
{
printf("error converting values\n");
exit(EXIT_FAILURE);
}
printf("i2 = %lu\n", i2);

return 0;
}


int str_to_ulongint(const char* str, unsigned long int* ulp)
{
int ret;
unsigned long int num;
char* p;
errno = 0;

if(NULL == str || '\0' == *str)
{
printf("Invalid Args\n");

Nit - only one argument is known to be invalid. ulp may or may not be
valid. The only invalid value I can think of is NULL and you never
test for that. It seems if you validate one argument, you should
validate them all.
return -1;

Everywhere else, you set ret and fall through to the "single exit" as
recommended by structured programming. Here you perform your own
exit. Would one more else have mattered that much?
}

p = NULL;

This serves no purpose since strtoul will not check this value and
will change it before returning.
num = strtoul(str, &p, 10);
/* Error check as per section 16.4 of H&S 5 */
if(ERANGE == errno)

Discussed else-thread.
{
if((0 == num) && (0 == strcmp(str, p)))

The only time strcmp returns 0 is when p == str. In that case, no
conversion was performed by strtoul and the contents of num are
guaranteed to be 0. The left operand of && is again redundant.

On the other hand, if errno is set to ERANGE, neither condition can be
true so this test needs to be outside the if(ERANGE... block of code.
{
printf("strtoul() could not convert string\n");
}
else if(ULONG_MAX == num)

If errno is set to ERANGE, this test is guaranteed to be true and
therefore superfluous.
{
printf("strtoul() overflow error\n");
}
else
{
printf("strange output from strtoul()\n");

And of course this code can never be reached.
}

perror("*ERROR*");
ret = -1;
}
else if((0 == errno) && (NULL != p && '\0' == *p))

p can never be NULL so that test serves no purpose.
{
printf("Successful Conversion by strtoul()\n");
*ulp = num;
ret = 1;
}
else
{
printf( "strange conversions and errno values :(\n");
printf( "num = %lu, ULONG_MAX = %lu", num, ULONG_MAX);
perror("*ERROR*");
ret = -1;
}

return ret;
}

============================= OUTPUT ===============================
[arnuld@dune programs]$ gcc -ansi -pedantic -Wall -Wextra str-to-ulong.c
[arnuld@dune programs]$ ./a.out
i = 127
arrc = 4294967295, strlen(arrc): 10

Successful Conversion by strtoul()
i = 4294967295

i2 = 128
arrc2 = 12345677899686848484, strlen(arrc2): 20

strtoul() overflow error
*ERROR*: Numerical result out of range
error converting values
[arnuld@dune programs]$
 
N

Nick Bowler

I wonder when sprintf can return a negative value. fprintf and printf
do so for I/O errors but that is not possible with sprintf.

The most obvious example of a failure that might occur with
(v)s(n)printf is when there is an encoding error processing the %lc or
%ls conversions. For instance, snprintf(NULL, 0, "%lc", (wint_t)-1)
returns -1 on my implementation.
 
A

arnuld

An unwarranted assumption (regarding ULONG_MAX)

I can't understand why everyone is complaining about this comment. I have
checked H&S 5, K&R2 and even section 5.4.2.1 of n1256.pdf and all of them
clearly state the maximum value of ULONG_MAX as 4294967295 (2^32 - 1) and
so I wrote code according to that.


Sine EOF is guaranteed to be negative, the left operand of || is
redundant.

I did not know that EOF is guaranteed to be negative, hence thanks.

I wonder when sprintf can return a negative value. fprintf and printf
do so for I/O errors but that is not possible with sprintf.

H&S5 section 15.11

The value returned by these fucntions is EOF if an error occured
during the output operation; otherwise result is some other EOF. In
standard C and most other implementations, the functions return the
number of characters sent to the output stream if no error occurs. In
case of sprintf, the count does not include the terminating null
character. (Standard C allows these functions to return any negative
value if an error occurs).

Look at last line. Standard C allows any negative value and hence my
check: if(0 > ret).



Another unwarranted assumption (regarding size_t).

Nit - only one argument is known to be invalid. ulp may or may not be
valid. The only invalid value I can think of is NULL and you never test
for that. It seems if you validate one argument, you should validate
them all.

Corrected

Everywhere else, you set ret and fall through to the "single exit" as
recommended by structured programming. Here you perform your own exit.
Would one more else have mattered that much?

Its a matter of style for me. I always put return statement if any of the
functions arguments are not proper, otherwise because of if-else the
program becomes too much of nested.
This serves no purpose since strtoul will not check this value and will
change it before returning.

see down for man page.

The only time strcmp returns 0 is when p == str. In that case, no
conversion was performed by strtoul and the contents of num are
guaranteed to be 0. The left operand of && is again redundant.

If errno is set to ERANGE, this test is guaranteed to be true and
therefore superfluous.

I don't know what exactly you mean here and I see this in the end of
section 16.4 of H&S 5:

if no conversion can be performed then these functions return 0, *ptr
is set to the value of str, and errno is set to ERANGE. if the number to
be converted would cause an overflow, then the functions return LONG_MAX,
LONG_MIN, LLONG_MAX, LLONG_MIN, ULONG_MAX, or ULLONG_MAX (depending on
the fucntions's return type and the sign of the value); errno is set tot
ERANGE;

So we have 2 types of errors here:

(1) one that would return 0
(2) that would return MAX/MIN of that type

(1) has 3 conditions to fulfill and (2) has only 1 condition and both (1)
and (2) have errno set to ERANGE

Same way I wrote the erro checking. Since there are 3 conditions
mentioned in (1) and all of them happen together, is there anything wrong
if you check all three instead of one ? I know checking ERANGE will
suffice but it won't tell me whether cause of error was overflow or no
conversion was performed.



And of course this code can never be reached.

You guarantee that it will never be reached, no matter what happens (like
if RAM gos bad) ?


p can never be NULL so that test serves no purpose.

man page strtoul (DESCRIPTION):

unsigned long int
strtoul(const char *nptr, char **endptr, int base);

If endptr is not NULL, strtoul() stores the address of the first
invalid character in *endptr. If there were no digits at all, strtoul()
stores the original value of nptr in *endptr (and returns 0). In
particular, if *nptr is not ‘\0’ but **endptr is ‘\0’ on return, the
entire string is valid.

According to first sentence of this description, I made a check for NULL
and 2nd, if I don't then 2nd check *p will segfault.
 
L

luser- -droog

man page strtoul (DESCRIPTION):

  unsigned long int
       strtoul(const char *nptr, char **endptr, int base);

  If  endptr is not NULL, strtoul() stores the address of the first
invalid character in *endptr.  If there were no digits at all, strtoul()
stores the original value of nptr in *endptr (and returns 0).   In  
particular, if *nptr is not ‘\0’ but **endptr is ‘\0’ on return, the
entire string is valid.

According to first sentence of this description, I made a check for NULL
and 2nd, if I don't then 2nd check *p will segfault.

--http://www.lispmachine.wordpress.com

Ah. But did you see this part?

NOTES
Since strtoul() can legitimately return 0 or LONG_MAX
(LLONG_MAX for strtoull()) on both success and failure, the
calling program should set errno to 0 before the call, and
then determine if an error occurred by checking whether errno
has a non-zero value after the call.

That sounds easier.
 
G

Georg Peter

Georg Peter said:
WANTED: To know the behavior of strtoul()
GOT: It works!
WHY POSTING: for improvements. [snip]
  num = strtoul(str, &p, 10);
  /* Error check as per section 16.4 of H&S 5 */
  if(ERANGE == errno)
I don't know about section 16.4 of H&S 5, but normally
errno is used in a different way: Errno usually has
only a defined meaning when a function returns a value
which indicates an error. AFAIK errno alone cannot be
used to find out if a function has succeeded or failed.

That seems to be at odds with this from section 7.5:

Which book you are citing here?
3.  The value of errno is zero at program startup, but is never set to
    zero by any library function.  The value of errno may be set to
    nonzero by a library function call whether or not there is an error,

This is the key point. A library function may succeed
and errno may have the value ERANGE. This can happen
when the library function a() calls another library
function b(). When b() fails and a() finds an alternate
way to succeed ernno still has the value set by b().
    provided the use of errno is not documented in the description of
    the function in this International Standard.

The fact that the description of strtoul does document the use of errno
means that strtoul may not set errno to nonzero other than as documented
in the function's description.

It's true that errno == ERANGE alone is not enough; you must ensure
that errno is zero before the call, but the OP's code does that.

This is complete nonsense, see the explanation above.
I am wondering, that I am the only person pointing this
out, since many good books say that setting errno to
zero and checking it after a library function call does
NOT work reliably.

Georg Peter
 
S

Seebs

I can't understand why everyone is complaining about this comment. I have
checked H&S 5, K&R2 and even section 5.4.2.1 of n1256.pdf and all of them
clearly state the maximum value of ULONG_MAX as 4294967295 (2^32 - 1) and
so I wrote code according to that.

No, no, NO. None of them state that.

They state that the *MINIMUM* value of ULONG_MAX is 2^32-1. ULONG_MAX may
be larger.

ULONG_MAX is the *maximum* value of unsigned long, which must be *at least*
2^32-1. Which is to say, 2^32-1 is the *minumum* allowed *maximum*.

-s
 
G

Georg Peter

Ben Bacarisse said:
Georg Peter said:
WANTED: To know the behavior of strtoul()
GOT: It works!
WHY POSTING: for improvements.
[snip]
  num = strtoul(str, &p, 10);
  /* Error check as per section 16.4 of H&S 5 */
  if(ERANGE == errno)
I don't know about section 16.4 of H&S 5, but normally
errno is used in a different way: Errno usually has
only a defined meaning when a function returns a value
which indicates an error. AFAIK errno alone cannot be
used to find out if a function has succeeded or failed.
That seems to be at odds with this from section 7.5:
3.  The value of errno is zero at program startup, but is never set to
    zero by any library function.  The value of errno may be set to
    nonzero by a library function call whether or not there is an error,
    provided the use of errno is not documented in the description of
    the function in this International Standard.
The fact that the description of strtoul does document the use of errno
means that strtoul may not set errno to nonzero other than as documented
in the function's description.
It's true that errno == ERANGE alone is not enough; you must ensure
that errno is zero before the call, but the OP's code does that.

Yes, and there's nothing that can happen between setting errno
to 0 and calling strtoul() that could set errno to a non-zero value.

Strtoul() or a function called by strtoul() could set
errno to non-zero and strtoul() can still succeed.

Errno ONLY has a reasonable value when the result of
the library function indicates that an error has happened.
Code like

errno = 0;
libraryFunction();
if (errno != 0) {

can NEVER reliably check if libraryFunction() has failed.

Georg Peter
 
A

arnuld

No, no, NO. None of them state that.

They state that the *MINIMUM* value of ULONG_MAX is 2^32-1. ULONG_MAX
may be larger.
ULONG_MAX is the *maximum* value of unsigned long, which must be *at
least* 2^32-1. Which is to say, 2^32-1 is the *minumum* allowed
*maximum*.

I think I am getting it now. So whats the maximum allowed ? (no book/
reference used the word *minimum*).

By same analogy: INT_MAX is the minimum value of INT_MAX for positive
side and INT_MIN is the maximum value for negative side (as -1 is greater
than -2 which is greater than -32767)

Am I right ?
 
L

Lew Pitcher

I think I am getting it now. So whats the maximum allowed ?

The standards do not define or delimit a /maximum/ maximum for any of
the data types
(no book/ reference used the word *minimum*).

The standards include wordings like:
"Their implementation-deï¬ned values shall be equal or greater in
magnitude (absolute value) to those
shown, with the same sign." (9899-1999 5.2.4.2.1 Size of Integer
Types")

The standards are written as much for compiler implementors as end
programmers, and set a minimum standard that the compilers must all
measure up to. Compiler implementors /may/ (for reasons of their own)
build compilers that exceed these requirements and still meet the
standard, but they can't build compilers that fall short of these
requirements and still call them "standard C" compilers.

Thus, /all/ "Standard C" compilers guarantee that an integer is /at
least/ 16 bits wide (UINT_MAX meets the minimum requirement of 65535).
Some compilers will take the permitted step and even make them 32 or
64 bits wide (with corresponding increases in UINT_MAX). The same goes
for long ints, and ULONG_MAX.
By same analogy: INT_MAX is the minimum value of INT_MAX  for positive
side and INT_MIN is the maximum value for negative side (as -1 is greater
than -2 which is greater than -32767)

Am I right ?

You've got it.

The standard guarantees a certain /minimum/ size for each data type.
It allows the implementors to exceed that /minimum size/, with
corresponding upward adjustments to the *_MIN and *_MAX macros that
reflect the implementation's data type sizes.

HTH
--
Lew Pitcher
Master Codewright & JOAT-in-training | Registered Linux User #112576
Me: http://pitcher.digitalfreehold.ca/ | Just Linux: http://justlinux.ca/
---------- Slackware - Because I know what I'm doing.
------
 
D

David Resnick

Georg Peter said:
WANTED: To know the behavior of strtoul()
GOT: It works!
WHY POSTING: for improvements.
[snip]
  num = strtoul(str, &p, 10);
  /* Error check as per section 16.4 of H&S 5 */
  if(ERANGE == errno)
I don't know about section 16.4 of H&S 5, but normally
errno is used in a different way: Errno usually has
only a defined meaning when a function returns a value
which indicates an error. AFAIK errno alone cannot be
used to find out if a function has succeeded or failed.
That seems to be at odds with this from section 7.5:

Which book you are citing here?
3.  The value of errno is zero at program startup, but is never set to
    zero by any library function.  The value of errno may be set to
    nonzero by a library function call whether or not there is an error,

This is the key point. A library function may succeed
and errno may have the value ERANGE. This can happen
when the library function a() calls another library
function b(). When b() fails and a() finds an alternate
way to succeed ernno still has the value set by b().
    provided the use of errno is not documented in the description of
    the function in this International Standard.
The fact that the description of strtoul does document the use of errno
means that strtoul may not set errno to nonzero other than as documented
in the function's description.
It's true that errno == ERANGE alone is not enough; you must ensure
that errno is zero before the call, but the OP's code does that.

This is complete nonsense, see the explanation above.
I am wondering, that I am the only person pointing this
out, since many good books say that setting errno to
zero and checking it after a library function call does
NOT work reliably.

Georg Peter

I believe that you are not correct. The "book" is the C-standard,
which is definitive with regards to the language (of course, if your
implementation doesn't conform to the standard, well, so be it). Here
are the two relevant parts:

errno definition:
[#3] The value of errno is zero at program startup, but is
never set to zero by any library function.159) The value of
errno may be set to nonzero by a library function call
whether or not there is an error, provided the use of errno
is not documented in the description of the function in this
International Standard.

strtol DOES document the use of errno. The above text would say that
if you set errno to 0 before the strtol call, a proper implementation
of strtol will not set errno except on error. Below is the definition
of strtoxxx in the standard with regard to errno.

[#8] The strtol, strtoll, strtoul, and strtoull functions
return the converted value, if any. If no conversion could
be performed, zero is returned. If the correct value is
outside the range of representable values, LONG_MIN,
LONG_MAX, LLONG_MIN, LLONG_MAX, ULONG_MAX, or ULLONG_MAX is
returned (according to the return type and sign of the
value, if any), and the value of the macro ERANGE is stored
in errno.

Seems clear enough to me. You are correct that checking errno after a
function call doesn't always work generically -- the standard says so
for functions that don't define the use of errno...

-David
 
G

Georg Peter

strtol DOES document the use of errno.

Many functions define errno values. This does NOT imply
that errno will be left unchanged when a function
succeeds.
   [#8] The strtol, strtoll, strtoul,  and  strtoull  functions
       return  the converted value, if any.  If no conversion could
       be performed, zero is returned.  If  the  correct  value  is
       outside   the   range  of  representable  values,  LONG_MIN,
       LONG_MAX, LLONG_MIN, LLONG_MAX, ULONG_MAX, or ULLONG_MAX  is
       returned  (according  to  the  return  type  and sign of the
       value, if any), and the value of the macro ERANGE is  stored
       in errno.

It does not state that errno stays unchanged when the
function succeeds. So errno could have the value ERANGE
altough the function succeeds. Assuming otherwise means
you depend on undefined behaviour. IMHO you need to
check for

zero, LONG_MIN and LONG_MAX for strtol()
zero, LLONG_MIN and LLONG_MAX for strtoll()
zero, ULONG_MAX for strtoul()
zero, ULLONG_MAX for strtoull()

and only when the function returns one of the values
mentioned above errno will have a defined value.
Seems clear enough to me.

For me also, see above.

Georg Peter
 
D

David Resnick

strtol DOES document the use of errno.

Many functions define errno values. This does NOT imply
that errno will be left unchanged when a function
succeeds.
   [#8] The strtol, strtoll, strtoul,  and  strtoull  functions
       return  the converted value, if any.  If no conversion could
       be performed, zero is returned.  If  the  correct  value  is
       outside   the   range  of  representable  values,  LONG_MIN,
       LONG_MAX, LLONG_MIN, LLONG_MAX, ULONG_MAX, or ULLONG_MAX  is
       returned  (according  to  the  return  type  and sign of the
       value, if any), and the value of the macro ERANGE is  stored
       in errno.

It does not state that errno stays unchanged when the
function succeeds. So errno could have the value ERANGE
altough the function succeeds. Assuming otherwise means
you depend on undefined behaviour. IMHO you need to
check for

  zero, LONG_MIN and LONG_MAX for strtol()
  zero, LLONG_MIN and LLONG_MAX for strtoll()
  zero, ULONG_MAX for strtoul()
  zero, ULLONG_MAX for strtoull()

and only when the function returns one of the values
mentioned above errno will have a defined value.
Seems clear enough to me.

For me also, see above.

Georg Peter

Hmmm. Again, the errno definition:
[#3] The value of errno is zero at program startup, but is
never set to zero by any library function.159) The value of
errno may be set to nonzero by a library function call
whether or not there is an error, provided the use of errno
is not documented in the description of the function in this
International Standard.

I believe this clearly means that *IF* a function in any way documents
its use of errno, it is constrained to only set it to non-zero under
the conditions documented. strtol documents the use of errno, and it
is thus so constrained to set errno according to that documentation.
Can't see how to read it any other way personally. By your logic,
seems to me that the clause "provided the use of..." in the errno
definition is rendered effectively meaningless.
 
S

Seebs

I think I am getting it now. So whats the maximum allowed ? (no book/
reference used the word *minimum*).

There isn't one. If you want to build an implementation that uses 256-bit
longs, you're allowed. 512, too. Whatever you want.

Let me walk you through the language in the standard. I'll use C99 TC3.

5.2.4.2.1 Sizes of integer types <limits.h>

The values given below shall be replaced by constant expressions
suitable for use in #if preprocessing directives. Moreover, except
for CHAR_BIT and MB_LEN_MAX, the following shall be replaced by
expressions that have the same type as would an expression that is
an object of the corresponding type converted according to the
integer promotions. Their implementation-defined values shall be
equal or greater in magnitude (absolute value) to those shown, with
the same sign.

The key sentence is the last one:
Their implementation-defined values shall be
equal or greater in magnitude (absolute value) to those shown, with
the same sign.

When they say "maximum value for an object of type unsigned long", what
they are doing is defining *what the symbol must represent*. On any
implementation, ULONG_MAX must be the maximum value for an object of type
unsigned long.

That value must be equal or greater in magnitude to 4294967295. There is
no limit as to how much greater.
By same analogy: INT_MAX is the minimum value of INT_MAX for positive
side and INT_MIN is the maximum value for negative side (as -1 is greater
than -2 which is greater than -32767)
Am I right ?

Sort of. I find it easier to think of the values in the standard as "minimum
magnitude". So INT_MIN must be a negative number which is at least as far
from 0 as -32767.

-s
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,011
Latest member
AjaUqq1950

Latest Threads

Top