strtol with hex greater than 4 byte ?

Discussion in 'C Programming' started by Peter Dunker, Apr 29, 2004.

  1. Peter Dunker

    Peter Dunker Guest

    Hi,

    I will check a String which should contain a HEX value.
    I know that strtol is the right function for this job.

    But what happens when I will check a hex string with 8 bytes?
    That I can check that the string is correct i know.

    long value;
    char src[]="0x1234567812345678"
    char *err;
    value = strtol(src,&err, 16);
    if (*err != 0x00)
    return -1; /*FEHLER*/

    The value is not 0x12345678 but I know it is right spelled.

    Is that C89 standard or only on my compiler/OS (VC6, Windows) ?

    Is there a way to get the right value of the beginning of the string,
    up to the sizeof(long) ?

    Thx
    Peter
     
    Peter Dunker, Apr 29, 2004
    #1
    1. Advertisements

  2. Peter Dunker

    Case Guest

    Note that in this case (string starts with "0x") you could set
    base to 0 and let strtol() figure it out. Just a remark; being
    explicit is usually a good programming habit. :)
    Unless long is 64-bit on your platform (which I assume is not, but
    rather 32-bit), strtol() processes the full src[] and overflows.
    According to K&R, page 252 LONG_MAX is returned, which is indeed
    not equal to 0x12345678. Also errno is set to ERANGE.
    Not that I know of, using standard library functions. In that case you
    must do it yourself. You could for example make a copy of the string
    up to sizeof long bytes and pass that copy to strtol().
     
    Case, Apr 29, 2004
    #2
    1. Advertisements

  3. Peter Dunker

    Peter Dunker Guest

    I know the possibility with 0, but the string should/must be a hex
    value, if there is a possibilty to get the used base after strtol is
    done, that will be create, but I don't think so.
    I have written a big "if" with str[0] and str[1] to check a x X 0x 0X
    at the beginning of the string and do then the strtol.
    Thx, that sounds interessting.
    OK I will do something like this, when I need the value.

    Thx
    Peter
     
    Peter Dunker, Apr 29, 2004
    #3
  4. Peter Dunker

    Case Guest

    According to K&R x and X do not make the string hexadecimal. Only 0x or
    0X are valid. So watch this! ---(What precisely do you want to catch
    with this test? I means, is the 0x or 0X the only thing you expect to
    go wrong possibly? Does this string come from user input?)---note
     
    Case, Apr 29, 2004
    #4
  5. Peter Dunker

    Dan Pop Guest

    It is C89, but your test is incorrect, as "0x1234567812345678" is of
    the expected form in its entirety and there is no final string, so err
    is guaranteed to point to the terminating null character:

    fangorn:~/tmp 756> cat test.c
    #include <stdio.h>
    #include <errno.h>
    #include <stdlib.h>
    #include <limits.h>

    int main()
    {
    long value;
    char src[]="0x1234567812345678";
    char *err;

    errno = 0;
    value = strtol(src, &err, 16);
    perror("strtol");
    printf("%ld %ld\n", value, LONG_MAX);
    printf("%d\n", *err);
    return 0;
    }
    fangorn:~/tmp 757> gcc test.c
    fangorn:~/tmp 758> ./a.out
    strtol: Numerical result out of range
    2147483647 2147483647
    0

    Which is exactly as documented: value is set to LONG_MAX, errno is set
    to ERANGE and err points to the terminating null character. Of course,
    the result would be different on a machine with 64-bit long's.

    It is a real PITA to perform error checking correctly after a strtol
    call:

    errno = 0;
    value = strtol(src, &err, 16);
    if (err == src) /* complete garbage input */ ;
    if (*err != 0) /* trailing garbage */ ;
    if ((value == LONG_MAX || value == LONG_MIN) && errno == ERANGE)
    /* overflow */;
    /* value contains the result of a successful conversion */ ;

    Depending on the application, the case of trailing garbage may not be
    considered an error.
    Yes. The easy way is to insert a null character at the right place in
    the input string. The hard way (when it is not guaranteed that the
    input string can be modified) is to generate a sscanf format specifying
    the maximum number of characters that should be converted and use it in
    an sscanf call.

    The hardest part is to compute the number of characters without
    making *any* assumptions. sizeof(long) * 2 + 2 assumes an 8-bit byte
    (and no padding bits). sizeof(long) * CHAR_BIT / 4 + 2 assumes a CHAR_BIT
    that is a multiple of 4 and no padding bits in the representation. So,
    you really have to start by "dissecting" LONG_MAX... And the easiest
    way of doing it is:

    char buff[sizeof(long) * CHAR_BIT / 3 + 2];
    sprintf(buff, "%lx", (unsigned long)LONG_MAX);

    Now, strlen(buff) + 2 is the bullet-proof solution to our problem.

    The C99 snprintf removes the need for allocating buff, but reduces the
    code portability (the SUS2 version of snprintf is useless for our purpose
    and many C89 implementations don't provide snprintf at all).

    Dan
     
    Dan Pop, Apr 29, 2004
    #5
  6. Peter Dunker

    Peter Dunker Guest

    According to K&R x and X do not make the string hexadecimal. Only 0x
    or
    very interessting.

    ---(What precisely do you want to catch
    I read a XML Document, and will check that every numbered value is in a
    special HEX format. If it is not, the user have to correct the
    Document.
    The correct Format is needed because I will save some information in my
    own data format, and will link to the string(hex) inside the parser
    implementation. So I don't need to copy all Data and out of my Program
    I know that hex_string[2] up to the the NULL pointer is the hex value
    in Bytes. (0x....)

    Thx for your hints
    Peter
     
    Peter Dunker, Apr 29, 2004
    #6
  7. Peter Dunker

    Sam Dennis Guest

    If my reading of the standard is correct, (errno == ERANGE) should
    suffice for this error condition (although you'll normally want to
    check whether it was too positive or too negative in the following
    code), as this `use' of errno is documented; implementations might
    set errno to some other non-zero value if there's no overflow, but
    ERANGE seems to be reserved. (This reading is likely mere wishful
    thinking; it seems far more likely that the intent is to prevent a
    different value from being used under circumstances wherein one is
    already prescribed.)
     
    Sam Dennis, Apr 29, 2004
    #7
  8. Peter Dunker

    Peter Dunker Guest

    THX

    New Question, what is different between the || and | (&& and &)
    I read anthing about that but I can't remember.
    Is the if also correct if you use the & and | ?
     
    Peter Dunker, Apr 29, 2004
    #8
  9. Peter Dunker

    Dan Pop Guest

    If strtol is not returning LONG_MAX or LONG_MIN, what is preventing it
    from setting errno to ERANGE?

    The strtol usage of errno is documented *only* for the cases when
    the return value is LONG_MAX or LONG_MIN.

    The general rule is to ignore errno unless the function signals an error.

    Dan
     
    Dan Pop, Apr 29, 2004
    #9
  10. Peter Dunker

    Dan Pop Guest

    Read again, until you can remember. It's a basic feature of the language.
    Actually, it's trivial to remember, once you have *really* understood the
    differences between them.
    In that particular case, yes. However, compare

    if (x != 0 && 1.0 / x > FOO) ...

    and

    if (x != 0 & 1.0 / x > FOO) ...

    and try to figure out which is correct and why.

    Dan
     
    Dan Pop, Apr 29, 2004
    #10
  11. 7.5p3 ... 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.
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    Hence, errno will only be set in that case.

    What am I missing?
     
    Peter Nilsson, Apr 30, 2004
    #11
    1. Advertisements

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 (here). After that, you can post your question and our members will help you out.