strtoul() behavior


G

Georg Peter

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.
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.

In other words: When errno is mentioned in the function
description you assume that errno stays unchanged when
the function succeeds.

This is WRONG because of the following reasons:

1. Many function descriptions contain phrases like:

... in case of error ... is stored in errno.

IMHO this does NOT mean that "the use of errno is
documented" for this function. It just specifies the
values errno will have in case of error. E.g.:
The manpage of fopen() contains the sentence:

Upon successful completion fopen(), fdopen() and
freopen() return a FILE pointer. Otherwise, NULL
is returned and errno is set to indicate the error.

But fopen() is definitely NOT a function where you can
check errno to find out if fopen() succeeded. With your
logic the success of many other library functions
could be checked by ckecking errno.

2. Your description of strtol, strtoll, strtoul and
strtoull mentiones errno only once. And it just
says that errno gets the value ERANGE when the
correct value is outside the range of representable
values. It does NOT say that errno is left unchanged
when the function succeeds.
By your logic, seems to me that the clause
"provided the use of..." in the errno
definition is rendered effectively meaningless.

No, the clause "provided the use of..." is NOT
meaningless. IMHO

If the correct value is outside the range of
representable values ... the value of the macro
ERANGE is stored in errno.

is NOT a sentence which describes the use of errno,
since it does NOT define what happens with errno
when the function succeeds.

Describing the USE of errno would be much more.
The USE of errno could be described with an example
like:

errno = 0;
function();
if (errno == 0) {
...

But such a use example is NOT present for strtoul().
Just describing a possible value for errno does
NOT describe the use of errno.

Georg Peter
 
Ad

Advertisements

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.

In other words: When errno is mentioned in the function
description you assume that errno stays unchanged when
the function succeeds.

This is WRONG because of the following reasons:

1. Many function descriptions contain phrases like:

  ... in case of error ... is stored in errno.

IMHO this does NOT mean that "the use of errno is
documented" for this function. It just specifies the
values errno will have in case of error. E.g.:
The manpage of fopen() contains the sentence:

  Upon successful completion fopen(), fdopen() and
  freopen() return a FILE pointer.  Otherwise, NULL
  is returned and errno is set to indicate the error.

But fopen() is definitely NOT a function where you can
check errno to find out if fopen() succeeded. With your
logic the success of many other library functions
could be checked by ckecking errno.

2. Your description of strtol, strtoll, strtoul and
   strtoull mentiones errno only once. And it just
   says that errno gets the value ERANGE when the
   correct value is outside the range of representable
   values. It does NOT say that errno is left unchanged
   when the function succeeds.
By your logic, seems to me that the clause
"provided the use of..." in the errno
definition is rendered effectively meaningless.

No, the clause "provided the use of..." is NOT
meaningless. IMHO

  If the correct value is outside the range of
  representable values ... the value of the macro
  ERANGE is stored in errno.

is NOT a sentence which describes the use of errno,
since it does NOT define what happens with errno
when the function succeeds.

Describing the USE of errno would be much more.
The USE of errno could be described with an example
like:

  errno = 0;
  function();
  if (errno == 0) {
    ...

But such a use example is NOT present for strtoul().
Just describing a possible value for errno does
NOT describe the use of errno.

Georg Peter

The place where you are not correct is in your use of implementation
behavior instead of the standard, I believe. You use fopen and a man
page as an example of why you can't look at errno for success/
failure. You are right there, but not for the reason you assert. The
C-standard does not in any way document errno behavior for the library
function fopen. It is therefore up to the implementation, and falls
into the "not documented" category. I believe it is the most
straightforward interpretation of the C-standard that ANY library
function that has mentions errno has "documented the use" of it and
therefore need not have add caveats like "on success, errno will not
be set" in order to conform. I can't see a different way to read the
errno definition.

But I guess we'll have to just disagree on this point.

-David
 
J

James Kuyper

On 01/06/2011 03:39 PM, Georg Peter wrote:
....
No, the clause "provided the use of..." is NOT
meaningless. IMHO

If the correct value is outside the range of
representable values ... the value of the macro
ERANGE is stored in errno.

is NOT a sentence which describes the use of errno,
since it does NOT define what happens with errno
when the function succeeds.

Describing the USE of errno would be much more.
The USE of errno could be described with an example
like:

errno = 0;
function();
if (errno == 0) {
...

But such a use example is NOT present for strtoul().
Just describing a possible value for errno does
NOT describe the use of errno.

With your of what it means to document the use of errno, is there ANY
standard library function where the use of errno IS documented? I don't
believe that there is. If I'm correct about that, then while the clause
may, in principle, be meaningful, removing it would have no effect on
the meaning of the standard. This does not prove that your
interpretation is incorrect, but it does strongly suggest that it might be.
 
D

David Resnick

The place where you are not correct is in your use of implementation
behavior instead of the standard, I believe.  You use fopen and a man
page as an example of why you can't look at errno for success/
failure.  You are right there, but not for the reason you assert.  The
C-standard does not in any way document errno behavior for the library
function fopen.  It is therefore up to the implementation, and falls
into the "not documented" category.  I believe it is the most
straightforward interpretation of the C-standard that ANY library
function that has mentions errno has "documented the use" of it and
therefore need not have add caveats like "on success, errno will not
be set" in order to conform.  I can't see a different way to read the
errno definition.

But I guess we'll have to just disagree on this point.

And BTW, I personally don't check errno absent a reason to do so
(error return). But still don't think the C standard is correctly
interpreted to mean what you say. The POSIX standards are more in
line with your interpretation, perhaps that is where your arguments
come from? e.g. if you look here: http://www.opengroup.org/onlinepubs/009604499/functions/errno.html
That has pretty much the semantics you are describing. Doesn't
override the C standard with regard to C library functions however...

-David



-David
 
B

Ben Bacarisse

Georg Peter said:
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.

There are a few things to unravel here. First, a detail. I am almost
certain you are wrong about a zero return. The text defining strtoul
does not document what errno will be if strtoul returns zero when no
conversion could be performed so nothing can be gained by looking at
errno in this case.

If I am wrong about this detail then GNU's C library has a bug rendering
it non-conforming: it returns 0 when presented with, say, "abc" and
leaves errno untouched.

Secondly, as a practical matter, I agree 100%. One should only examine
errno after an error return that has one or more documented errno values
associated with it. However, I have always done this in the belief that
it protects against rogue library functions that use errno in some
non-conforming way; or simply out of habit from the wild days before
ANSI C when there was, pretty much, a free-for-all on library functions
setting errno (except that, even then, they never set errno no zero).

Neither of these really addresses your main point: that errno is only
reliable when the function has returned an "error value" (I put it in
scare quotes because UINT_MAX is no obviously an error -- simply an
indication that there might be an error). You main point is addressed
by paragraph 3 of section 7.5:

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 point has been raised that the final qualification is pointless if
you are correct, but I am not sure that it's as simple as that. For
example, if stroul called (in some specific cases) a function like atoi
that does not document the use of errno then it could be argued that any
setting of errno is not being done a library function that documents the
use of errno.

However, this seems to me to be stretching the wording beyond what is
reasonable, but I would certainly welcome some more views on this
matter.
For me also, see above.

So, now, the only thing that is clear is that it isn't!
 
L

lawrence.jones

David Resnick said:
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.

That was certainly the intent.
 
Ad

Advertisements

B

Barry Schwarz

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

There is no 5.4.2.1 in n1256. I think you meant 5.2.4.2.1 and others
have already explained how you misread it.
clearly state the maximum value of ULONG_MAX as 4294967295 (2^32 - 1) and
so I wrote code according to that.

I wonder what tool you are using for quoting. In the message I saw,
these statements were on two separate lines. When I quoted it back to
you, they were still on separate lines, each preceded with a '>'. How
did you get them on the same line and strip the intervening '>'?
I did not know that EOF is guaranteed to be negative, hence thanks.



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).

H&S is irrelevant. Stick to the standard. In section 7.19.6, the
*printf functions, including sprintf, are defined in terms of
fprintf. fprintf returns "a negative value if an output or encoding
error occurred." Output errors are obviously I/O errors and encoding
errors appear to be related to multi-byte character sets. sprintf
does not perform I/O and you don't appear to be using multi-byte
characters so I still wonder what could cause sprintf to generate a
negative return.
Corrected



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.


see down for man page.

You are misunderstanding what strtoul does with endptr. See down for
details.
I don't know what exactly you mean here and I see this in the end of
section 16.4 of H&S 5:

Since you went to the trouble to snip the code I commented on, I'm not
surprised.
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

The only error that returns 0 is when no conversion can be performed.
(2) that would return MAX/MIN of that type

The only error that returns ULONG_MAX is the one and only error that
also causes errno to be set to ERANGE. Since you have already tested
and found errno set to ERANGE, testing for ULONG_MAX is a waste of
time.
(1) has 3 conditions to fulfill and (2) has only 1 condition and both (1)
and (2) have errno set to ERANGE

I have no idea what this means and only condition 2 sets errno 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.






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

If RAM goes bad, it will print you national identity number, bank
account numbers, and every password stored on your system to every
newsgroup in Usenet.
man page strtoul (DESCRIPTION):

Man pages are irrelevant. And you are still misreading it. If &p is
not NULL, the strtoul will store a non-NULL value in p.
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.

While technically legal as syntax, *nptr has type char* and therefore
should never be thought of as having the value '\0'. If it were to
have a zero value, it should be referred to as NULL or 0 but never
imply it is a char.

Furthermore, if endptr is not NULL, *endptr is guaranteed to be not
NULL when strtoul returns.
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.

You don't pass p to strtoul, you pass &p. Consequently, the value in
p itself is not passed to the function, the address of p is passed.
The parameter endptr in the function description therefore has the
value &p. strtoul does not check to see if *endptr (which is the
value in p) is NULL because it doesn't care. It does check to see if
endptr is NULL. If it is, it obviously does not store anything in
*endptr. If endptr is not NULL, the strtoul will store the address of
the first invalid character in *endptr completely replacing the NULL
value you stored there.

One more time, strtoul does not use the value in p, it replaces that
value.
 
A

arnuld

I wonder what tool you are using for quoting. In the message I saw,
these statements were on two separate lines. When I quoted it back to
you, they were still on separate lines, each preceded with a '>'. How
did you get them on the same line and strip the intervening '>'?

I myself don't know why they get on same line. BTW, I use Pan.



H&S is irrelevant. Stick to the standard. In section 7.19.6, the
*printf functions, including sprintf, are defined in terms of fprintf.
fprintf returns "a negative value if an output or encoding error
occurred." Output errors are obviously I/O errors and encoding errors
appear to be related to multi-byte character sets. sprintf does not
perform I/O and you don't appear to be using multi-byte characters so I
still wonder what could cause sprintf to generate a negative return.

Okay, from 7.19.6.6

The sprintf function returns the number of characters written in the
array, not counting the terminating null character, or a negative value
if an encoding error occurred.

So sprintf() returns negative value on error (don't know exactly what
*encoding* means here).



Since you went to the trouble to snip the code I commented on, I'm not
surprised.

:-\ . Sorry, did not intend to surprise you.






The only error that returns ULONG_MAX is the one and only error that
also causes errno to be set to ERANGE. Since you have already tested
and found errno set to ERANGE, testing for ULONG_MAX is a waste of time.

ERNAGE is set in 2 conditons: when no conversion is performed and 2nd
when overflow will occur. I was trying to distinguish between them with
my error-checks. I think that information can be useful on solving
problems in future.



You don't pass p to strtoul, you pass &p. Consequently, the value in p
itself is not passed to the function, the address of p is passed. The
parameter endptr in the function description therefore has the value &p.
strtoul does not check to see if *endptr (which is the value in p) is
NULL because it doesn't care. It does check to see if endptr is NULL.
If it is, it obviously does not store anything in *endptr. If endptr is
not NULL, the strtoul will store the address of the first invalid
character in *endptr completely replacing the NULL value you stored
there.

One more time, strtoul does not use the value in p, it replaces that
value.


Last line made me understand everything :)
 
B

Barry Schwarz

I myself don't know why they get on same line. BTW, I use Pan.





Okay, from 7.19.6.6

The sprintf function returns the number of characters written in the
array, not counting the terminating null character, or a negative value
if an encoding error occurred.

So sprintf() returns negative value on error (don't know exactly what
*encoding* means here).

As I said, encoding errors seem to be related to multi-byte characters
which you are not using.
:-\ . Sorry, did not intend to surprise you.








ERNAGE is set in 2 conditons: when no conversion is performed and 2nd
when overflow will occur. I was trying to distinguish between them with
my error-checks. I think that information can be useful on solving
problems in future.

Read 7.20.1.4-8 again. There are two separate conditions in separate
sentences:

If no conversion, then 0 is returned

If the converted value is outside the range, then errno is set
to ERANGE.

If errno were set for the first case, there would have been some words
to the effect that the clause describing it being sent applied to both
cases.
Last line made me understand everything :)

Glad to help.
 
I

ImpalerCore

Last line made me understand everything :)

I remember having issues learning strtoul. To help further your
understanding, here is a relatively simple example of using strtoul
that I use to parse ISO 8601 duration strings (for just dates,
ignoring the time components). Unfortunately, I haven't taken the
time to replace my framework stuff to make a standalone example, but
hopefully it will give you a better idea on how you can use it.

\code snippet
/*!
* \brief Define a structure to store a date duration from the
* Gregorian calendar in component form.
*
* The structure of a duration can be made up of a combination of
* years, months, and days. The date duration is used to describe a
* logical length of time independent of Gregorian dates.
*
* In contrast with \c c_greg_date, the \c int type is used to
* represent duration components because the magnitude of individual
* components may be larger than <tt>INT8_MAX</tt>.
*/
struct c_greg_date_duration
{
/*! \brief The year component. */
int year;

/*! \brief The month component. */
int month;

/*! \brief The day component. */
int day;
};

static const struct c_greg_date_duration gc_invalid_greg_date_duration
= { -1, -1, -1 };

struct c_greg_date_duration
c_date_duration_from_iso_string( const char* iso_str )
{
struct c_greg_date_duration duration = { 0, 0, 0 };
long value;
char* strtoul_endp;

bool year_found = false;
bool month_found = false;
bool day_found = false;
bool week_found = false;

c_return_value_if_fail( iso_str != NULL,
gc_invalid_greg_date_duration );

/* Leading space in the ISO 8601 date string is ignored. */
while ( c_ascii_isspace( *iso_str ) ) {
++iso_str;
}

/* If the date string is all whitespace, the date format is invalid.
*/
if ( *iso_str == '\0' ) {
return gc_invalid_greg_date_duration;
}

/*
* If the duration string does not start with a 'P', the duration
* format is invalid.
*/
if ( *iso_str != 'P' ) {
return gc_invalid_greg_date_duration;
}
++iso_str;

while ( c_ascii_isalnum( *iso_str ) )
{
/*
* The next section parses the date. Here are the two valid
* ISO 8601 date duration formats (P[n]W or P[n]Y[n]M[n]D). Note
* that zero value components of a duration can be omitted. A
* number is required before one of 'Y', 'M', 'D', or 'W' fields.
*
* On an implementation note, using 'strtoul' will reject any
* negative numbers preceding one of the 'Y', 'M', 'D', or 'W'
* fields.
*/
value = strtoul( iso_str, &strtoul_endp, GC_BASE_DECIMAL );

if ( strtoul_endp - iso_str == 0 ) {
return gc_invalid_greg_date_duration;
}

if ( *strtoul_endp == 'Y' )
{
/*
* The 'year_found' checks for multiple '[n]Y' fields. The
* 'month_found' and 'day_found' checks that the year field
* precedes the month and day field in 'P[n]Y[n]M[n]D'. The
* 'week_found' field checks that the 'P[n]W' format is not
* mixed with the 'P[n]Y[n]M[n]D' format.
*/
if ( year_found || month_found || day_found || week_found ) {
return gc_invalid_greg_date_duration;
}

duration.year = value;
year_found = true;
}
else if ( *strtoul_endp == 'M' )
{
/*
* The 'month_found' checks for multiple '[n]M' fields. The
* 'day_found' checks that the month field precedes the day
field
* in 'P[n]Y[n]M[n]D'. The 'week_found' field checks that the
* 'P[n]W' format is not mixed with the 'P[n]Y[n]M[n]D' format.
*/
if ( month_found || day_found || week_found ) {
return gc_invalid_greg_date_duration;
}

duration.month = value;
month_found = true;
}
else if ( *strtoul_endp == 'D' )
{
/*
* The 'day_found' checks for multiple '[n]D' fields. The
* 'week_found' field checks that the 'P[n]W' format is not
mixed
* with the 'P[n]Y[n]M[n]D' format.
*/
if ( day_found || week_found ) {
return gc_invalid_greg_date_duration;
}

duration.day = value;
day_found = true;
}
else if ( *strtoul_endp == 'W' )
{
/*
* The 'week_found' checks for multiple '[n]W' fields. The
* 'year_found', 'month_found', and 'day_found' checks that the
* 'P[n]W' format is not mixed with the 'P[n]Y[n]M[n]D' format.
*/
if ( week_found || year_found || month_found || day_found ) {
return gc_invalid_greg_date_duration;
}

duration.day = value * C_DAYS_IN_WEEK;
week_found = true;
}
else {
return gc_invalid_greg_date_duration;
}

iso_str = strtoul_endp;
++iso_str;
}

/*
* Trailing whitespace is allowed when parsing the ISO 8601
* duration string.
*/
while ( c_ascii_isspace( *iso_str ) ) {
++iso_str;
}

return *iso_str == '\0' ? duration : gc_invalid_greg_date_duration;
}
\endcode

This example ignores ERANGE issues, or any conversion issues storing a
long value into an int. In fact, I didn't even realize that strtoul
could set errno until this thread. I'm not exactly sure how kosher my
using strtoul to parse an unsigned number but store in a long is
either. I'm sure the code critics will let me know soon enough :)

Best regards,
John D.
 
J

James Waldby

[Re: int ret = sprintf(arrc, "%lu", ULONG_MAX); if(EOF == ret || 0 > ret)
]
I myself don't know why they get on same line. BTW, I use Pan.

[OT in c.l.c]

When it quotes a post, Pan 0.132 wraps short lines. If you use
an external editor to edit a reply, the same wrapping occurs as
with Pan's internal editor. I don't know of a way to control
that behavior (other than manually unwrapping the wrapped lines
while editing a reply). The behavior is independent of Pan's
"Wrap Article Body" switch, which toggles wrapping on or off in
the display of article text.
 
Ad

Advertisements

A

arnuld

As I said, encoding errors seem to be related to multi-byte characters
which you are not using.

Oh.. now I got it.




Read 7.20.1.4-8 again. There are two separate conditions in separate
sentences:

If no conversion, then 0 is returned

If the converted value is outside the range, then errno is set
to ERANGE.

If errno were set for the first case, there would have been some words
to the effect that the clause describing it being sent applied to both
cases.


I agree on this. I wonder why H&S 5 (being such a reputed and recommended
says different). I mostly use H&S but now I think I have to reply on
n1256 first.
 
T

Tim Rentsch

Georg Peter said:
strtol DOES document the use of 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.
It does not state that errno stays unchanged when the
function succeeds.

That is true, but irrelevant.
So errno could have the value ERANGE
altough the function succeeds. [snip elaboration]

No. One might imagine that it could, but doing so is
outside what the Standard allows implementations to do.
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.

In other words: When errno is mentioned in the function
description you assume that errno stays unchanged when
the function succeeds.

This is WRONG because of the following reasons:

[snip example not from ISO documents]

2. Your description of strtol, strtoll, strtoul and
strtoull mentiones errno only once. And it just
says that errno gets the value ERANGE when the
correct value is outside the range of representable
values. It does NOT say that errno is left unchanged
when the function succeeds.

Again, that is true but irrelevant. Read the condition again -
'provided the use of errno is not documented'. The condition
doesn't say "fully documented" or "clearly documented" or
"completely documented", just "documented". There is no doubt
that, in the cited paragraph, use of errno _is documented_. It
might not be documented the way you like, or as explicitly as one
might wish, but certainly it is documented. And that means the
license to set errno given in 7.5p3 does not apply.
No, the clause "provided the use of..." is NOT
meaningless. IMHO

If the correct value is outside the range of
representable values ... the value of the macro
ERANGE is stored in errno.

is NOT a sentence which describes the use of errno,
since it does NOT define what happens with errno
when the function succeeds.

Describing the USE of errno would be much more.
The USE of errno could be described with an example
like:

errno = 0;
function();
if (errno == 0) {
...

But such a use example is NOT present for strtoul().
Just describing a possible value for errno does
NOT describe the use of errno.

You are focusing on the word 'use' but not on the more important
word 'documented'. There is no doubt that use of errno for the
function strtoul() _is documented_ in its description, because
the document gives circumstances of its use. Whether that
section "describes" the use of errno, or any other more elaborate
condition, just doesn't matter. Use of errno _is documented_ in
the description of the strtoul()-related functions, and that's
the only thing that counts.
 
G

Georg Peter

Georg Peter said:
strtol DOES document the use of errno.
[snip]
   [#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.

That is true, but irrelevant.

I want to point out some things.
You probably know that C was designed to implement
Unix. Unix inspired Posix and its descendants like SUS.
Operating systems like Unix, Linux, BSD and Mac OSX all
implement Posix (more or less). And Posix describes
hundreds of functions which use errno in exactly the
way I described: Errno has only a reliable meaning
when a function returns a value that indicates an
error (and the function says that errno would be
set).

When C defines a different usage philosophy for
errno it cuts off its roots. I assume that the people
defining the C standard are smart. When they really
changed the errno logic, they made a bad decision.

People reading this thread might come to the wrong
conclusion that all functions using errno can be
used like in the example below:

errno = 0;
some_function();
if (errno != 0) {
/* some_function() had an error */

But this is NOT true for Posix functions. For the
Posix function some_function() you write:

/* It makes no sense to set errno since it might */
/* be changed even when some_function() succeeds. */
if (some_function() == ERROR_RESULT_OF_SOME_FUNCTION) {
/* some_function() had an error and only then */
/* errno indicates which error happened */
printf("errno=%d\n", errno);
...
} else
/* errno can have any value. */
/* some_function() might have changed errno */
/* although some_function() succeeded. */
/* You simply cannot use errno reliable when */
/* some_function() succeeded. */

Note that Posix functions have different values which
indicate an error so ERROR_RESULT_OF_SOME_FUNCTION
is specific to some_function().

Georg Peter
 
D

David Resnick

But this is NOT true for Posix functions. For the
Posix function some_function() you write:

You started this by telling someone that they were wrong with regard
to their use of errno in strtoul. I believe it has been shown that
you are simply incorrect in that regard. A more general case, or
POSIX usage, is not relevant to that point. Nor does the POSIX
standard override the C standard in a discussion about C.

If your message is that people should use errno in the way POSIX
defines as a general idea (only check on error) and to be consistent
across functions that do and do not document their errno usage, fine.
I use it that way myself, and from this discussion so do a bunch of
others who are nonetheless arguing against your interpretation with
regard to strtoul and C.

-David
 
K

Keith Thompson

arnuld said:
Oh.. now I got it.


I agree on this. I wonder why H&S 5 (being such a reputed and recommended
says different). I mostly use H&S but now I think I have to reply on
n1256 first.

Yes, this does appear to be an error in H&S 5, and it's not mentioned
in the errata on careferencemanual.com. I've reported the error and
attempted to Cc you on the e-mail, giving you credit for finding it
of course . If you don't get the e-mail, drop me a line and I'll
forward it.
 
Ad

Advertisements

N

Nick Bowler

You started this by telling someone that they were wrong with regard to
their use of errno in strtoul. I believe it has been shown that you are
simply incorrect in that regard. A more general case, or POSIX usage,
is not relevant to that point. Nor does the POSIX standard override the
C standard in a discussion about C.

If your message is that people should use errno in the way POSIX defines
as a general idea (only check on error) and to be consistent across
functions that do and do not document their errno usage, fine. I use it
that way myself, and from this discussion so do a bunch of others who
are nonetheless arguing against your interpretation with regard to
strtoul and C.

OT: POSIX has the following to say about strtoul and errno:

The strtoul() function shall not change the setting of errno if successful.

Since 0, {ULONG_MAX}, and {ULLONG_MAX} are returned on error and are also
valid returns on success, an application wishing to check for error
situations should set errno to 0, then call strtoul() or strtoull(), then
check errno.
 
D

David Resnick

OT: POSIX has the following to say about strtoul and errno:

  The strtoul() function shall not change the setting of errno if successful.

  Since 0, {ULONG_MAX}, and {ULLONG_MAX} are returned on error and are also
  valid returns on success, an application wishing to check for error
  situations should set errno to 0, then call strtoul() or strtoull(), then
  check errno.

Yep, saw that when I looked.

You might also note this here (http://pubs.opengroup.org/onlinepubs/
009695399/functions/strtoul.html), not sure how the two are squared:

The functionality described on this reference page is aligned with the
ISO C standard. Any conflict between the requirements described here
and the ISO C standard is unintentional. This volume of IEEE Std
1003.1-2001 defers to the ISO C standard.

-David
 
G

Georg Peter

OT: POSIX has the following to say about strtoul and errno:

  The strtoul() function shall not change the setting of errno if successful.

This makes it clear. The function strtoul() obviously
uses errno in a different way compared to other POSIX
functions. I have to admit that I learned something new.

Georg Peter
 
Ad

Advertisements

A

arnuld

Yes, this does appear to be an error in H&S 5, and it's not mentioned in
the errata on careferencemanual.com. I've reported the error and
attempted to Cc you on the e-mail, giving you credit for finding it of
course . If you don't get the e-mail, drop me a line and I'll forward
it.

I did get it and sent you a reply too. Thanks a ton :)
 

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

Similar Threads

perror()4 says SUCCESS 10
pointer to pointer 7
Binary Search in C 7
wcstombs() problem 16
array-size/malloc limit and strlen() failure 26
Remving an element from Queue 37
using a pointer vs array 12
Selection-Sort in C 35

Top