Casting int from char pointer

Discussion in 'C Programming' started by Test, Apr 19, 2011.

  1. Test

    Test Guest

    I have:

    int xx;
    char *buf;

    buf is pointed to a string with int values, for example:

    buf=(char *)malloc(4);
    buf[0]=0;
    buf[1]=0;
    buf[2]=178;
    buf[3]=3;
    etc.

    I want xx to have the int value of 946 from buf[2] and buf[3].
    I can do it like this:

    memcpy( &xx, &buffer[2], 2 );

    or

    ((char *)(&xx))[0]=buffer[2];
    ((char *)(&xx))[1]=buffer[3];


    Both look clumsy. How would I cast it more elegantly.

    My target is win32 if that matters.
     
    Test, Apr 19, 2011
    #1
    1. Advertising

  2. On Tue, 19 Apr 2011 14:02:21 -0400, Test <test@.nil.invalid.com> wrote:

    > I have:
    >
    > int xx;
    > char *buf;
    >
    > buf is pointed to a string with int values, for example:
    >
    > buf=(char *)malloc(4);
    > buf[0]=0;
    > buf[1]=0;
    > buf[2]=178;
    > buf[3]=3;
    > etc.
    >
    > I want xx to have the int value of 946 from buf[2] and buf[3].
    > I can do it like this:
    >
    > memcpy( &xx, &buffer[2], 2 );
    >
    > or
    >
    > ((char *)(&xx))[0]=buffer[2];
    > ((char *)(&xx))[1]=buffer[3];
    >
    >
    > Both look clumsy. How would I cast it more elegantly.


    Avoiding non-portable assumptions about endian-ness and int sizes,
    why not
    xx = (buf[2] << 8) + buf[3];

    > My target is win32 if that matters.

    Best not to write code for which the target machine would matter.


    --
    Morris Keesan --
     
    Morris Keesan, Apr 19, 2011
    #2
    1. Advertising

  3. Test

    Ben Pfaff Guest

    Test <test@.nil.invalid.com> writes:

    > I want xx to have the int value of 946 from buf[2] and buf[3].
    > I can do it like this:
    >
    > memcpy( &xx, &buffer[2], 2 );
    >
    > or
    >
    > ((char *)(&xx))[0]=buffer[2];
    > ((char *)(&xx))[1]=buffer[3];
    >
    >
    > Both look clumsy. How would I cast it more elegantly.
    >
    > My target is win32 if that matters.


    "int" is only 2 bytes on Win32? I am surprised. I would have
    guessed 4. If "int" is not exactly 2 bytes long, then neither of
    your approaches will work. If it is, on the other hand, then I'd
    suggest the first solution.
    --
    "All code should be deliberately written for the purposes of instruction.
    If your code isn't readable, it isn't finished yet."
    --Richard Heathfield
     
    Ben Pfaff, Apr 19, 2011
    #3
  4. On 4/19/2011 2:02 PM, Test wrote:
    > I have:
    >
    > int xx;
    > char *buf;
    >
    > buf is pointed to a string with int values, for example:
    >
    > buf=(char *)malloc(4);

    ^^^^^^^^
    The cast is unnecessary, and most unnecessary things introduced into
    code are unwise. The cast tells anyone reading this that there is
    something special which requires it. Don't cause unnecessary headaches
    for anyone reading your code.

    > buf[0]=0;
    > buf[1]=0;
    > buf[2]=178;

    ^^^
    This is not portable. If you want the buffer to contained unsigned
    chars, declare buf as a pointer to unsigned char.

    > buf[3]=3;
    > etc.
    >
    > I want xx to have the int value of 946 from buf[2] and buf[3].
    > I can do it like this:
    >
    > memcpy(&xx,&buffer[2], 2 );


    No, you can't. This presumes
    1) a particular size for char
    2) a particular size for int
    3) a particular byte order within ints
    4) a particular signedness for char

    > or


    > ((char *)(&xx))[0]=buffer[2];
    > ((char *)(&xx))[1]=buffer[3];


    No, you can't, for the same reasons. Besides being unreasonably messy.

    >
    > Both look clumsy. How would I cast it more elegantly.


    Stop thinking about casts. You simply shift the value in buffer[3] an
    appropriate number of bits and add the value in buffer[2]. No casts, no
    silly pointer tricks, mo memcpy.
     
    Martin Ambuhl, Apr 19, 2011
    #4
  5. Test

    John Gordon Guest

    In <ioknmm$v3v$> Martin Ambuhl <> writes:

    > No, you can't. This presumes
    > 1) a particular size for char


    Isn't sizeof(char) guaranteed to be 1?

    --
    John Gordon A is for Amy, who fell down the stairs
    B is for Basil, assaulted by bears
    -- Edward Gorey, "The Gashlycrumb Tinies"
     
    John Gordon, Apr 19, 2011
    #5
  6. John Gordon <> writes:
    > In <ioknmm$v3v$> Martin Ambuhl <> writes:
    >
    >> No, you can't. This presumes
    >> 1) a particular size for char

    >
    > Isn't sizeof(char) guaranteed to be 1?


    Yes.

    But the code in question appeared to assume that an int is 2 bytes.
    I suppose one could say either than (a) it assumes int is 2 bytes,
    or (b) it assumes char is 8 bits and int is 16 bits.

    (Incidentally, int is 32 bits, or 4 8-bit bytes, in win32, which is the
    OP's environment.)

    Determining exactly which questionable assumptions the code made is
    probably less useful than actually fixing it.

    --
    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, Apr 19, 2011
    #6
  7. Test

    James Kuyper Guest

    On 04/19/2011 03:59 PM, John Gordon wrote:
    > In <ioknmm$v3v$> Martin Ambuhl <> writes:
    >
    >> No, you can't. This presumes
    >> 1) a particular size for char

    >
    > Isn't sizeof(char) guaranteed to be 1?


    Yes, but I think he was referring to the size in bits, rather than the
    size in bytes. CHAR_BITS can be greater than 8.
    --
    James Kuyper
     
    James Kuyper, Apr 19, 2011
    #7
  8. On 4/19/2011 3:59 PM, John Gordon wrote:
    > In<ioknmm$v3v$> Martin Ambuhl<> writes:
    >
    >> No, you can't. This presumes
    >> 1) a particular size for char

    >
    > Isn't sizeof(char) guaranteed to be 1?


    Indeed, sizeof(char) = 1, but that is precisely in units of
    sizeof(char). There are, as I'm sure you know, more meanings for the
    size of a region of storage than simply the result of the operator
    sizeof. How large, for example, how large would a char be on a GE 645
    running multics? The result of sizeof(char) would certainly be 1, but
    the on the GE645 the norm for character storage was four 9-bit chars in
    a 36-bit word. His assumption of octets would surely land him hot water.
     
    Martin Ambuhl, Apr 19, 2011
    #8
  9. Test

    Ike Naar Guest

    On 2011-04-19, James Kuyper <> wrote:
    > On 04/19/2011 03:59 PM, John Gordon wrote:
    > Yes, but I think he was referring to the size in bits, rather than the
    > size in bytes. CHAR_BITS can be greater than 8.


    Nit: it's CHAR_BIT .
     
    Ike Naar, Apr 19, 2011
    #9
  10. Test <test@.nil.invalid.com> wrote:
    > I have:
    >
    > int xx;
    > char *buf;

    ....
    > I want xx to have the int value of 946 from buf[2] and buf[3].

    <snip>

    <http://c-faq.com/stdio/extconform.html>

    --
    Peter
     
    Peter Nilsson, Apr 19, 2011
    #10
  11. "Morris Keesan" <> writes:

    > On Tue, 19 Apr 2011 14:02:21 -0400, Test <test@.nil.invalid.com> wrote:
    >
    >> I have:
    >>
    >> int xx;
    >> char *buf;
    >>
    >> buf is pointed to a string with int values, for example:
    >>
    >> buf=(char *)malloc(4);
    >> buf[0]=0;
    >> buf[1]=0;
    >> buf[2]=178;
    >> buf[3]=3;
    >> etc.

    <snip>
    > Avoiding non-portable assumptions about endian-ness and int sizes,
    > why not
    > xx = (buf[2] << 8) + buf[3];


    It's not as simple as that. A couple of posters have suggested that
    this is all that is needed, but to avoid assumptions about int sizes you
    need to work harder.

    (1) char could be signed and buf[2] negative so the shift could be
    undefined.

    (2) If we make buf unsigned char, it will still probably promote to int
    so the arithmetic value of the shift may be unrepresentable in the
    result type. That also makes it undefined.

    (3) If we cast to unsigned int (i.e. (unsigned int)buf[2] << 8) the
    result may be too large to assign to an int without triggering
    implementation defined behaviour or (worse) the raising of an
    implementation defined signal.

    There are, of course, ways round all this but, frankly, I'd write what
    you have done 99 times out of 100. I've only had to do this once in a
    library that needed to give strong portability assurances, and I did it
    your way there too, but that was in K&R1 days so I could just wave my
    hands an talk about what will "probably happen on most systems".

    All of the above problems assume C99. In C90 ("ANSI C") the wording is
    more vague, so while buf[2] << 8 can't be undefined, the exact value of
    a signed shift is not 100 clear to me.

    <snip>
    --
    Ben.
     
    Ben Bacarisse, Apr 20, 2011
    #11
  12. Test

    Test Guest

    "Morris Keesan" <> wrote:

    >On Tue, 19 Apr 2011 14:02:21 -0400, Test <test@.nil.invalid.com> wrote:
    >
    >> I have:
    >>
    >> int xx;
    >> char *buf;
    >>
    >> buf is pointed to a string with int values, for example:
    >>
    >> buf=(char *)malloc(4);
    >> buf[0]=0;
    >> buf[1]=0;
    >> buf[2]=178;
    >> buf[3]=3;
    >> etc.
    >>
    >> I want xx to have the int value of 946 from buf[2] and buf[3].
    >> I can do it like this:
    >>
    >> memcpy( &xx, &buffer[2], 2 );
    >>
    >> or
    >>
    >> ((char *)(&xx))[0]=buffer[2];
    >> ((char *)(&xx))[1]=buffer[3];
    >>
    >>
    >> Both look clumsy. How would I cast it more elegantly.

    >
    >Avoiding non-portable assumptions about endian-ness and int sizes,
    >why not
    > xx = (buf[2] << 8) + buf[3];
    >
    >> My target is win32 if that matters.

    >Best not to write code for which the target machine would matter.


    For my purpose
    xx = (buf[3] << 8) + buf[2];

    was correct. Thank you for your post.
    This code was ported from 16-bit to 32 and xx never exceeds FF FF. After some
    testing it seems that the old clumsy looking is slightly faster.
     
    Test, Apr 20, 2011
    #12
  13. Test

    James Kuyper Guest

    On 04/20/2011 03:47 AM, Test wrote:
    > "Morris Keesan" <> wrote:
    >
    >> On Tue, 19 Apr 2011 14:02:21 -0400, Test <test@.nil.invalid.com> wrote:
    >>
    >>> I have:
    >>>
    >>> int xx;
    >>> char *buf;
    >>>
    >>> buf is pointed to a string with int values, for example:
    >>>
    >>> buf=(char *)malloc(4);
    >>> buf[0]=0;
    >>> buf[1]=0;
    >>> buf[2]=178;
    >>> buf[3]=3;
    >>> etc.
    >>>
    >>> I want xx to have the int value of 946 from buf[2] and buf[3].
    >>> I can do it like this:
    >>>
    >>> memcpy( &xx, &buffer[2], 2 );
    >>>
    >>> or
    >>>
    >>> ((char *)(&xx))[0]=buffer[2];
    >>> ((char *)(&xx))[1]=buffer[3];
    >>>
    >>>
    >>> Both look clumsy. How would I cast it more elegantly.

    >>
    >> Avoiding non-portable assumptions about endian-ness and int sizes,
    >> why not
    >> xx = (buf[2] << 8) + buf[3];
    >>
    >>> My target is win32 if that matters.

    >> Best not to write code for which the target machine would matter.

    >
    > For my purpose
    > xx = (buf[3] << 8) + buf[2];
    >
    > was correct. Thank you for your post.
    > This code was ported from 16-bit to 32 and xx never exceeds FF FF. After some
    > testing it seems that the old clumsy looking is slightly faster.


    Which do you prefer: getting the wrong answer fast, or the right answer
    more slowly?
    The clumsy code will give the wrong results on a wide variety of
    systems. If you're absolutely certain that this code will never be
    ported to any machine where it will produce incorrect results, leave it
    as is. Please note that such certainty is usually self-delusional. If
    you're actually in touch with reality, use the shift-and-add approach,
    which is far more portable, even if it turns out to be slower on some
    platforms.

    --
    James Kuyper
     
    James Kuyper, Apr 20, 2011
    #13
  14. James Kuyper <> writes:

    > On 04/20/2011 03:47 AM, Test wrote:
    >> "Morris Keesan" <> wrote:
    >>
    >>> On Tue, 19 Apr 2011 14:02:21 -0400, Test <test@.nil.invalid.com> wrote:
    >>>
    >>>> I have:
    >>>>
    >>>> int xx;
    >>>> char *buf;

    <snip>
    >>>> ((char *)(&xx))[0]=buffer[2];
    >>>> ((char *)(&xx))[1]=buffer[3];
    >>>>

    <snip>
    >> For my purpose
    >> xx = (buf[3] << 8) + buf[2];
    >>
    >> was correct. Thank you for your post.
    >> This code was ported from 16-bit to 32 and xx never exceeds FF FF. After some
    >> testing it seems that the old clumsy looking is slightly faster.

    >
    > Which do you prefer: getting the wrong answer fast, or the right answer
    > more slowly?
    > The clumsy code will give the wrong results on a wide variety of
    > systems. If you're absolutely certain that this code will never be
    > ported to any machine where it will produce incorrect results, leave it
    > as is. Please note that such certainty is usually self-delusional. If
    > you're actually in touch with reality, use the shift-and-add approach,
    > which is far more portable, even if it turns out to be slower on some
    > platforms.


    But this code may also fail on some systems because char might be
    signed. To the OP: change buf to be an unsigned char array and you
    remove one of the pitfalls from this shifting code.

    --
    Ben.
     
    Ben Bacarisse, Apr 20, 2011
    #14
    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. Schnoffos
    Replies:
    2
    Views:
    1,227
    Martien Verbruggen
    Jun 27, 2003
  2. trey

    newbie: char* int and char *int

    trey, Sep 10, 2003, in forum: C Programming
    Replies:
    7
    Views:
    406
    Irrwahn Grausewitz
    Sep 10, 2003
  3. Hal Styli
    Replies:
    14
    Views:
    1,657
    Old Wolf
    Jan 20, 2004
  4. Abhishek

    Casting a file pointer to char pointer

    Abhishek, Mar 21, 2006, in forum: C Programming
    Replies:
    9
    Views:
    657
    santosh
    Mar 22, 2006
  5. gert
    Replies:
    20
    Views:
    1,177
Loading...

Share This Page