How can I cast a char to an unsigned int?

34,012

Solution 1

unsigned int val = (unsigned char)bytes[0] << CHAR_BIT | (unsigned char)bytes[1];

This if sizeof(unsigned int) >= 2 * sizeof(unsigned char) (not something guaranteed by the C standard)

Now... The interesting things here is surely the order of operators (in many years still I can remember only +, -, * and /... Shame on me :-), so I always put as many brackets I can). [] is king. Second is the (cast). Third is the << and fourth is the | (if you use the + instead of the |, remember that + is more importan than << so you'll need brakets)

We don't need to upcast to (unsigned integer) the two (unsigned char) because there is the integral promotion that will do it for us for one, and for the other it should be an automatic Arithmetic Conversion.

I'll add that if you want less headaches:

unsigned int val = (unsigned char)bytes[0] << CHAR_BIT;
val |= (unsigned char)bytes[1];

Solution 2

unsigned int val = (unsigned char) bytes[0]<<8 | (unsigned char) bytes[1];

Solution 3

The byte ordering depends on the endianness of your processor. You can do this, which will work on big or little endian machines. (without ntohs it will work on big-endian):

unsigned int val = ntohs(*(uint16_t*)bytes)
Share:
34,012
RLH
Author by

RLH

Updated on July 05, 2022

Comments

  • RLH
    RLH almost 2 years

    I have a char array that is really used as a byte array and not for storing text. In the array, there are two specific bytes that represent a numeric value that I need to store into an unsigned int value. The code below explains the setup.

    char* bytes = bytes[2];
    bytes[0] = 0x0C; // For the sake of this example, I'm 
    bytes[1] = 0x88; // assigning random values to the char array.
    
    unsigned int val = ???; // This needs to be the actual numeric 
                            // value of the two bytes in the char array.  
                            // In other words, the value should equal 0x0C88;
    

    I can not figure out how to do this. I would assume it would involve some casting and recasting of the pointers, but I can not get this to work. How can I accomplish my end goal?

    UPDATE

    Thank you Martin B for the quick response, however this doesn't work. Specifically, in my case the two bytes are 0x00 and 0xbc. Obviously what I want is 0x000000bc. But what I'm getting in my unsigned int is 0xffffffbc.

    The code that was posted by Martin was my actual, original code and works fine so long as all of the bytes are less than 128 (.i.e. positive signed char values.)

  • xanatos
    xanatos over 12 years
    I couldn't resist it... It was so black & white :-)
  • Oliver Charlesworth
    Oliver Charlesworth over 12 years
    Strictly speaking, this will invoke integer overflow (if char is signed by default) when the msb of bytes[0] is set.
  • xanatos
    xanatos over 12 years
    I'll add that there is a half km long of warnings. Nowhere in the standard it's written that a byte is only 8 bit :-)
  • Martin Beckett
    Martin Beckett over 12 years
    @xanatos, didn't realise `` and 4spaces formatted code differently
  • Mooing Duck
    Mooing Duck over 12 years
    I don't think that will work, since ntohs will read in too many bytes.
  • Piotr Praszmo
    Piotr Praszmo over 12 years
    You need parentheses around << operation and this won't work with negative values.
  • Oliver Charlesworth
    Oliver Charlesworth over 12 years
    @Banthar: You don't need the parentheses, although it's probably advisable from a readability point of view.
  • Oliver Charlesworth
    Oliver Charlesworth over 12 years
    In fact, I retract my earlier comment! It simply won't work properly if char is signed.
  • TJD
    TJD over 12 years
    @MooingDuck, it will work, ntohs is for 16-bit values. ntohl is for 32-bits
  • Oliver Charlesworth
    Oliver Charlesworth over 12 years
    Strictly speaking, this still relies on type aliasing.
  • Oliver Charlesworth
    Oliver Charlesworth over 12 years
    +1: The only answer so far that does it properly. The cast to unsigned int is unnecessary, though.
  • Mooing Duck
    Mooing Duck over 12 years
    oh, correct. However, *(unsigned int*)bytes will read in too many bytes.
  • Mooing Duck
    Mooing Duck over 12 years
    Better, but it's possible that this will have alignment problems. Wait, I don't think this question has anything to do with endian-ness...
  • TJD
    TJD over 12 years
    You have to worry about endianness if you map a 16-bit pointer to it. If you do (uint16_t) on little endian, val == 0x880C. On big-endian, val == 0xC88. Alignment point is true, but extremely hard to find a processor these days that can't do unaligned accesses, even in the embedded world.
  • Jens Erat
    Jens Erat over 12 years
    @MooingDuck I indeed missed casting, but << has higher precedence than |, so no paranthesis are need in my version.
  • Mooing Duck
    Mooing Duck over 12 years
    On that last line, val |= ... might be faster.
  • Christoph
    Christoph over 12 years
    @MooingDuck: C99 allows type-punning through unions - a footnote which makes this explicit was added to section 6.5.2.3 with TC3 in 2007; however, Chuck's code assumes little-endian byte order - shifting is the portable solution
  • Oliver Charlesworth
    Oliver Charlesworth over 12 years
    @TJD: It's not that difficult. It's fairly common for DSP ISAs to not support unaligned accesses, for instance.
  • Mooing Duck
    Mooing Duck over 12 years
    @Christoph: It's illegal in C++, my mistake. I can't remove my -1 until it's edited :(
  • RLH
    RLH over 12 years
    Your first line of code has solved the problem. However, I've also tried the last snippet before posting this question. That was one "solution" that simply didn't work.
  • Christoph
    Christoph over 12 years
    @MooingDuck: added a missing semicolon, so fire away ;)