C 铸造uint8至int8

C 铸造uint8至int8,c,microchip,xc8,C,Microchip,Xc8,使用微芯片XC8我有一个结构 int16_t test; uint8_t msb = 0xff; uint8_t lsb = 0xf4; uint8_t hyst = 0xff; test = ((((int16_t)msb)<<8) + (int16_t)lsb) + (int8_t)hyst); int16\t测试; uint8_t msb=0xff; uint8_t lsb=0xf4; uint8_t hyst=0xff; test=(((int16_t)msb)正如Ol

使用微芯片XC8我有一个结构

int16_t test;
uint8_t msb = 0xff;
uint8_t lsb = 0xf4;
uint8_t hyst = 0xff; 

test = ((((int16_t)msb)<<8) + (int16_t)lsb) + (int8_t)hyst);
int16\t测试;
uint8_t msb=0xff;
uint8_t lsb=0xf4;
uint8_t hyst=0xff;

test=(((int16_t)msb)正如Olaf正确地指出的,如果
int
的宽度为16,则移位操作可能没有定义的行为,因为您正在将位移位到
int16_t
的符号位中。那么,您的代码是错误的,您无法推断平台可能实现的值

如果
int
较大,则表达式一切正常,您只需将适合
int
的正值相加。但由于初始化,结果值将转换回
int16\t
,这将导致“实现定义”转换或信号的提升。因此,您应该检查编译器文档,看看您的平台在这些情况下会做些什么,如果可以的话,最好避免这种情况。

注释中的OK

int16_t test;
uint8_t msb = 0xff;
uint8_t lsb = 0xf4;
uint8_t hyst = 0xff; 

test = (int16_t)(((uint16_t)msb)<<8) + (uint16_t)lsb) + (int8_t)hyst;
int16\t测试;
uint8_t msb=0xff;
uint8_t lsb=0xf4;
uint8_t hyst=0xff;

test=(int16_t)((uint16_t)msb)标准整数转换和未定义行为。如果
int
由于左移而为16位,则这是未定义行为。什么是
sizeof(int)
?那么它是UB。如果将
((int16_t)msb)
更改为
((uint16_t)msb)
,您将摆脱未定义的行为,尽管它仍然是实现定义的。对
int16\t
的转换是多余的,只是降低了可读性,因为这些值无论如何都将提升为int。只有当
int
为16位时才是未定义的,因为整数提升是在移位之前执行的。@interjay,s请参见我的编辑,在另一种情况下,UB正在转换为
int16\u t
。如果int更大,则转换为
int16\u t
将由实现定义。如果从
int
int16\u t
的转换中存在溢出,则该溢出的行为由实现定义(它可以是一个实现定义的信号,但在现代体系结构上,甚至在嵌入式体系结构上也不是很常见)。出于某种原因,对于非法使用带符号的左移位,您喜欢使用“未定义行为”这样的绕口语,但它被明确命名为“未定义行为”在标准中。由于有人坚持让其他人使用mot just(),因此只需按照标准中的要求来称呼它就更简单了。一般来说,您不应该混合使用有符号和无符号。如果您组装位字段,通常使用无符号。