从外部源将两个字节的数据转换为16位带符号整数的正确方法是使用如下辅助函数:
#include <stdint.h>
int16_t be16_to_cpu_signed(const uint8_t data[static 2]) {
uint32_t val = (((uint32_t)data[0]) << 8) |
(((uint32_t)data[1]) << 0);
return ((int32_t) val) - 0x10000u;
}
int16_t le16_to_cpu_signed(const uint8_t data[static 2]) {
uint32_t val = (((uint32_t)data[0]) << 0) |
(((uint32_t)data[1]) << 8);
return ((int32_t) val) - 0x10000u;
}
上面的哪个函数合适,取决于数组包含小端还是大端表示。字节序不是这里要讨论的问题,我想知道为什么zwol0x10000u
从uint32_t
转换为的值中减去int32_t
。
为什么这是正确的方法?
转换为返回类型时,如何避免实现定义的行为?
由于可以假设2的补码表示形式,因此这种更简单的转换将失败: return (uint16_t)val;
这个天真的解决方案有什么问题:
int16_t le16_to_cpu_signed(const uint8_t data[static 2]) {
return (uint16_t)data[0] | ((uint16_t)data[1] << 8);
}
int16_t
0xFFFF0001u
不能表示为int16_t
,在第二种方法0xFFFFu
中,不能表示为int16_t
。
int16_t
是实现定义的,因此幼稚的方法不可移植。