C - 三个字节变成一个有符号整数

C - three bytes into one signed int

我有一个传感器,它以三个字节的形式给出输出。我是这样读的:

unsigned char byte0,byte1,byte2;

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

现在我要把这三个字节合并成一个数:

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

它给我的值从 0 到 16,777,215,但我期望值从 -8,388,608 到 8,388,607。我虽然 int 已经由其实施签署。即使我尝试像 signed int value; 那样定义它,它仍然只给我正数。所以我想我的问题是如何将 int 转换为其补码?

谢谢!

您需要执行的操作称为签名扩展。您有 24 个有效位,但想要 32 个有效位(请注意,您假设 int 为 32 位宽,这并不总是正确的;您最好使用 [=13= 中定义的类型 int32_t ]).丢失的 8 个最高位应该是正值的全零或负值的全 1。它由 24 位值的最高有效位定义。

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:请注意,您不能将 8 位值移动 8 位或更多位,这是未定义的行为。您必须先将其转换为更宽的类型。

#include <stdint.h>
uint8_t byte0,byte1,byte2;
int32_t answer;

// assuming reg 0x25 is the signed MSB of the number 
// but you need to read unsigned for some reason
byte0=readRegister(0x25);
byte1=readRegister(0x26);
byte2=readRegister(0x27);

// so the trick is you need to get the byte to sign extend to 32 bits
// so force it signed then cast it up
answer = (int32_t)((int8_t)byte0); // this should sign extend the number
answer <<= 8;
answer |= (int32_t)byte1; // this should just make 8 bit field, not extended
answer <<= 8;
answer |= (int32_t)byte2;

这也应该有效

answer = (((int32_t)((int8_t)byte0))<<16) + (((int32_t)byte1)<< 8) + byte2;

我可能对括号过于激进,但我从不相信自己会使用移位运算符:)