C-将三个字节转换为一个有符号整数

C-将三个字节转换为一个有符号整数,c,twos-complement,signed-integer,C,Twos Complement,Signed Integer,我有一个传感器,它的输出是三个字节。我是这样读的: unsigned char byte0,byte1,byte2; byte0=readRegister(0x25); byte1=readRegister(0x26); byte2=readRegister(0x27); 现在我想把这三个字节合并成一个数字: int value; value=byte0 + (byte1 << 8) + (byte2 << 16); int值; value=byte0+(byte1

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

unsigned char byte0,byte1,byte2;

byte0=readRegister(0x25);
byte1=readRegister(0x26);
byte2=readRegister(0x27);
现在我想把这三个字节合并成一个数字:

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

value=byte0+(byte1您需要执行的是符号扩展。您有24个有效位,但需要32个有效位(请注意,您假设
int
为32位宽,这并不总是正确的;您最好使用
stdint.h
中定义的类型
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);
int32\t值;
uint8_t extension=byte2&0x80?0xff:00;/*检查位7*/
value=(int32_t)字节0((int32_t)字节1
#include
字节0,字节1,字节2;
int32_t回答;
//假设reg 0x25是数字的有符号MSB
//但出于某种原因,您需要阅读unsigned
字节0=读取寄存器(0x25);
字节1=读取寄存器(0x26);
字节2=读取寄存器(0x27);
//所以关键是你需要把要签名的字节扩展到32位
//所以,强迫它签名,然后抛出它
answer=(int32_t)((int8_t)字节0);//这应该是数字的符号扩展

回答:你不应该假设
int
是2的补码或任何其他实现细节。这最多会导致不可移植和脆弱的代码。只需自己做算术就可以得到正确的结果。事实上,你甚至不应该假设它可以容纳3字节的数字!在你的体系结构中int的大小是多少?不要假设 int
或甚至
char
。使用适当的类型,如
uint8\u t
int32\u t
等。在标准的下一个版本中,下划线可以解决这个问题,因为在实践中,对于任何可能被积极更新或新编写的代码,非二补算法似乎都不会成为IRL的问题。@Stan即使使用signed类型,即(未)签名的扩展,它仅由编译器执行,而不是由程序员执行。了解它背后的底层逻辑是很好的。有时您必须知道如何自己执行:1)您无法控制输入值的签名性(第三方代码)2)编译器不支持您所需的整数类型(例如,13位有符号整数或256位有符号整数)。整数提升应用于
@Leushenko的操作数,谢谢,我不知道
char
在移位操作中有特殊处理。但是,在C中移位时,你再小心也不为过。@Leushenko:确实,如果不冒未定义行为的风险,就不能将八位值移位八位。
128@GrigoryRechistov:这不是移位操作中对字符的特殊处理。在C语言中,所有整数表达式(包括字符、字符)在大多数上下文中至少提升为int。
#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;