这是将数组转换为数字的安全方法吗?
// 23 FD 15 94 -> 603788692
char number[4] = {0x94, 0x15, 0xFD, 0x23};
uint32_t* n = (uint32_t*)number;
printf("number is %lu", *n);
更多信息
我在具有 LSB 架构的嵌入式设备中使用它,不需要便携。我目前正在使用移位,但如果这段代码是安全的,我更喜欢它。
这是将数组转换为数字的安全方法吗?
// 23 FD 15 94 -> 603788692
char number[4] = {0x94, 0x15, 0xFD, 0x23};
uint32_t* n = (uint32_t*)number;
printf("number is %lu", *n);
更多信息
我在具有 LSB 架构的嵌入式设备中使用它,不需要便携。我目前正在使用移位,但如果这段代码是安全的,我更喜欢它。
不,这不安全。
这违反了 C 别名规则,即只能通过其自己的类型、其有符号/无符号变体或通过字符类型访问对象。它还可以通过中断对齐来调用未定义的行为。
uint32_t
从数组中获取值的安全解决方案是对值使用按位运算符 ( <<
and &
)char
以形成uint32_t
.
不,只有当它是一个整数时,你才被允许以整数的形式访问它 。
但这里是你可以通过简单地改变逻辑来操纵对象的二进制表示的方法:
uint32_t n;
unsigned char * p = (unsigned char *)&n;
assert(sizeof n == 4); // assumes CHAR_BIT == 8
p[0] = 0x94; p[1] = 0x15; p[2] = 0xFD; p[3] = 0x23;
寓意:您可以将每个对象视为字节序列,但不能将任意字节序列视为任何特定对象。
此外,一种类型的二进制表示非常依赖于平台,因此不知道您从中得到什么实际整数值。如果您只想从其基数 256 位合成一个整数值,请使用普通数学:
uint32_t n = 0x94 + (0x15 * 0x100) + (0xFD * 0x10000) + (0x23 * 0x1000000);
这是完全独立于平台的,并且纯粹根据值而不是表示来表达您想要的东西。把它留给你的编译器来生成代码的机器表示。
你最好用这样的东西(更便携):
int n = (c[3]<<24)|(c[2]<<16)|(c[1]<<8)|c[0];
其中 c 是一个无符号字符数组。