strtoul() behavior

Discussion in 'C Programming' started by arnuld, Jan 5, 2011.

  1. arnuld

    arnuld Guest

    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]$



    --
    http://www.lispmachine.wordpress.com
    arnuld, Jan 5, 2011
    #1
    1. Advertising

  2. arnuld

    Ike Naar Guest

    On 2011-01-05, arnuld <> wrote:
    > 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.
    Ike Naar, Jan 5, 2011
    #2
    1. Advertising

  3. arnuld <> writes:

    > 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>
    --
    Ben.
    Ben Bacarisse, Jan 5, 2011
    #3
  4. arnuld

    Georg Peter Guest

    On 5 Jan., 15:00, arnuld <> wrote:
    > 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
    Georg Peter, Jan 5, 2011
    #4
  5. Georg Peter <> writes:

    > On 5 Jan., 15:00, arnuld <> wrote:
    >> 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.

    --
    Ben.
    Ben Bacarisse, Jan 5, 2011
    #5
  6. Ben Bacarisse <> writes:
    > Georg Peter <> writes:
    >> On 5 Jan., 15:00, arnuld <> wrote:
    >>> 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)

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Nokia
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, Jan 6, 2011
    #6
  7. Keith Thompson <> writes:

    > Ben Bacarisse <> writes:
    >> Georg Peter <> writes:
    >>> On 5 Jan., 15:00, arnuld <> wrote:
    >>>> 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.

    --
    Ben.
    Ben Bacarisse, Jan 6, 2011
    #7
  8. On 05 Jan 2011 14:00:06 GMT, arnuld <> wrote:

    >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]$


    --
    Remove del for email
    Barry Schwarz, Jan 6, 2011
    #8
  9. arnuld

    Nick Bowler Guest

    On Wed, 05 Jan 2011 18:01:40 -0800, Barry Schwarz wrote:
    > 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.
    Nick Bowler, Jan 6, 2011
    #9
  10. arnuld

    arnuld Guest

    > On Wed, 05 Jan 2011 18:01:40 -0800, Barry Schwarz wrote:

    >> On 05 Jan 2011 14:00:06 GMT, arnuld <> wrote:
    >> /* unsigned long is 10 digits at maximum as per section 5.1.1 in H&s5
    >> */


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



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




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


    > Another unwarranted assumption (regarding size_t).


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


    Corrected


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


    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.

    >> p = NULL;

    >
    > This serves no purpose since strtoul will not check this value and will
    > change it before returning.


    see down for man page.


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


    > ..SNIP...


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




    >> else
    >> {
    >> printf("strange output from strtoul()\n");


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



    >> else if((0 == errno) && (NULL != p && '\0' == *p))

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




    --
    http://www.lispmachine.wordpress.com
    arnuld, Jan 6, 2011
    #10
  11. On Jan 6, 12:08 am, arnuld <> wrote:
    > > On Wed, 05 Jan 2011 18:01:40 -0800, Barry Schwarz wrote:
    > >> On 05 Jan 2011 14:00:06 GMT, arnuld <> wrote:


    > >>  else if((0 == errno) && (NULL != p && '\0' == *p))

    >
    > > 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.
    >
    > --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.
    luser- -droog, Jan 6, 2011
    #11
  12. arnuld

    Georg Peter Guest

    On 6 Jan., 00:13, Ben Bacarisse <> wrote:
    > Georg Peter <> writes:
    > > On 5 Jan., 15:00, arnuld <> wrote:
    > >> 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
    Georg Peter, Jan 6, 2011
    #12
  13. arnuld

    Seebs Guest

    On 2011-01-06, arnuld <> wrote:
    >> On Wed, 05 Jan 2011 18:01:40 -0800, Barry Schwarz wrote:
    >>> On 05 Jan 2011 14:00:06 GMT, arnuld <> wrote:
    >>> /* unsigned long is 10 digits at maximum as per section 5.1.1 in H&s5
    >>> */


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


    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
    --
    Copyright 2010, all wrongs reversed. Peter Seebach /
    http://www.seebs.net/log/ <-- lawsuits, religion, and funny pictures
    http://en.wikipedia.org/wiki/Fair_Game_(Scientology) <-- get educated!
    I am not speaking for my employer, although they do rent some of my opinions.
    Seebs, Jan 6, 2011
    #13
  14. arnuld

    Georg Peter Guest

    On 6 Jan., 01:00, Keith Thompson <> wrote:
    > Ben Bacarisse <> writes:
    > > Georg Peter <> writes:
    > >> On 5 Jan., 15:00, arnuld <> wrote:
    > >>> 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
    Georg Peter, Jan 6, 2011
    #14
  15. arnuld

    arnuld Guest

    > On Thu, 06 Jan 2011 08:27:57 +0000, Seebs wrote:


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




    --
    http://www.lispmachine.wordpress.com
    arnuld, Jan 6, 2011
    #15
  16. arnuld

    Lew Pitcher Guest

    On Jan 6, 7:35 am, arnuld <> wrote:
    > > On Thu, 06 Jan 2011 08:27:57 +0000, Seebs wrote:
    > > 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 ?


    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.

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


    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.
    ------
    Lew Pitcher, Jan 6, 2011
    #16
  17. On Jan 6, 3:23 am, Georg Peter <> wrote:
    > On 6 Jan., 00:13, Ben Bacarisse <> wrote:
    >
    >
    >
    > > Georg Peter <> writes:
    > > > On 5 Jan., 15:00, arnuld <> wrote:
    > > >> 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
    David Resnick, Jan 6, 2011
    #17
  18. arnuld

    Georg Peter Guest

    On 6 Jan., 17:40, David Resnick <> wrote:
    > On Jan 6, 3:23 am, Georg Peter <> wrote:
    > > On 6 Jan., 00:13, Ben Bacarisse <> wrote:
    > > > Georg Peter <> writes:
    > > > > On 5 Jan., 15:00, arnuld <> wrote:

    > 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
    Georg Peter, Jan 6, 2011
    #18
  19. On Jan 6, 2:21 pm, Georg Peter <> wrote:
    > On 6 Jan., 17:40, David Resnick <> wrote:
    >
    > > On Jan 6, 3:23 am, Georg Peter <> wrote:
    > > > On 6 Jan., 00:13, Ben Bacarisse <> wrote:
    > > > > Georg Peter <> writes:
    > > > > > On 5 Jan., 15:00, arnuld <> wrote:

    > > 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.
    David Resnick, Jan 6, 2011
    #19
  20. arnuld

    Seebs Guest

    On 2011-01-06, arnuld <> wrote:
    > 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
    --
    Copyright 2010, all wrongs reversed. Peter Seebach /
    http://www.seebs.net/log/ <-- lawsuits, religion, and funny pictures
    http://en.wikipedia.org/wiki/Fair_Game_(Scientology) <-- get educated!
    I am not speaking for my employer, although they do rent some of my opinions.
    Seebs, Jan 6, 2011
    #20
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Tim Hubberstey

    "Interesting" behavior with aggregates

    Tim Hubberstey, Jun 25, 2004, in forum: VHDL
    Replies:
    6
    Views:
    1,809
    Tim Hubberstey
    Jun 30, 2004
  2. Paul Butler

    Modelsim behavior

    Paul Butler, Aug 9, 2004, in forum: VHDL
    Replies:
    1
    Views:
    1,081
    Jonathan Bromley
    Aug 9, 2004
  3. Mantorok Redgormor
    Replies:
    70
    Views:
    1,711
    Dan Pop
    Feb 17, 2004
  4. Return Value of atoi and strtoul

    , Apr 16, 2007, in forum: C Programming
    Replies:
    4
    Views:
    852
    Flash Gordon
    Apr 17, 2007
  5. Ivan Shmakov

    strtoul () vs. errno

    Ivan Shmakov, May 4, 2012, in forum: C Programming
    Replies:
    3
    Views:
    530
    Bill Cunningham
    May 4, 2012
Loading...

Share This Page