ctwos-complementsigned-integer

C - three bytes into one signed int


I have a sensor which gives its output in three bytes. I read it like this:

unsigned char byte0,byte1,byte2;

byte0=readRegister(0x25);
byte1=readRegister(0x26);
byte2=readRegister(0x27);

Now I want these three bytes merged into one number:

int value;
value=byte0 + (byte1 << 8) + (byte2 << 16);

it gives me values from 0 to 16,777,215 but I'm expecting values from -8,388,608 to 8,388,607. I though that int was already signed by its implementation. Even if I try define it like signed int value; it still gives me only positive numbers. So I guess my question is how to convert int to its two's complement?

Thanks!


Solution

  • What you need to perform is called sign extension. You have 24 significant bits but want 32 significant bits (note that you assume int to be 32-bit wide, which is not always true; you'd better use type int32_t defined in stdint.h). Missing 8 top bits should be either all zeroes for positive values or all ones for negative. It is defined by the most significant bit of the 24 bit value.

    int32_t value;
    uint8_t extension = byte2 & 0x80 ? 0xff:00; /* checks bit 7 */
    value = (int32_t)byte0 | ((int32_t)byte1 << 8) | ((int32_t)byte2 << 16) | ((int32_t)extension << 24);
    

    EDIT: Note that you cannot shift an 8 bit value by 8 or more bits, it is undefined behavior. You'll have to cast it to a wider type first.