【发布时间】:2020-07-06 22:05:03
【问题描述】:
在this answer,zwol 提出了这样的声明:
将来自外部源的两个字节数据转换为 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;
}
上面的哪个函数是合适的取决于数组是包含小端还是大端表示。字节序不是这里的问题,我想知道为什么 zwol 从转换为 int32_t 的 uint32_t 值中减去 0x10000u。
为什么这是正确的方法?
在转换为返回类型时如何避免实现定义的行为?
既然你可以假设 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时的确切行为是实现定义的,因此这种幼稚的方法是不可移植的。 -
@nwellnhof 没有演员表
int16_t -
标题中的问题不指定使用哪个映射就无法回答
-
两种方法都依赖于实现定义的行为(将无符号值转换为不能表示该值的有符号类型)。例如。在第一种方法中,
0xFFFF0001u不能表示为int16_t,而在第二种方法中,0xFFFFu不能表示为int16_t。 -
“因为你可以假设 2 的补码表示”[需要引用]。 C89 和 C99 当然不否认 1 的补码和符号幅度表示。 Q.v.,stackoverflow.com/questions/12276957/…
标签: c casting language-lawyer