假设我有这个数组:
uint8_t arr[10];
位于地址0x00
。
然后我想将其中的一部分分配给uint32_t值。 arr [1],arr [2],arr [3]和arr [4]的聚合为32位整数。这是一个例子:
uint8_t arr[10];
uint32_t i;
i = *( (uint32_t *)&arr[1] );
困扰我的是arr[1]
位于地址不是四的倍数(地址0x01)。所以问题是:32位平台会发生什么?这是合法的吗,与标准uint32
作业相比,它有哪些缺点?
答案 0 :(得分:5)
这是非法的,因为它违反了严格的别名规则,导致undefined behaviour。
改为使用memcpy
:
memcpy(&i, &arr[1], sizeof(i));
但请注意,此代码假定主机字节序。如果您需要与字节顺序无关的代码,请使用位移和屏蔽将4个值组合为整数,或在memcpy
之后交换字节(编译器通常会为此提供某种内在函数)。
答案 1 :(得分:3)
类型惩罚违反了有效类型规则,即C标准第6.5节第6和第7节。这些表示您无权访问与声明的类型不同的对象。 (这些规则有一些复杂的例外情况,但在这里不适用。)
这样做会使您的程序处于未定义状态,并且可能会发生错误。根据经验,除非你确切知道自己在做什么,否则永远不要做指针演员。
如果你真的需要在字节表示和另一种类型之间切换,最简单的方法是使用union
union twist {
unsigned char c[sizeof(uint32_t)];
uint32_t u;
} val = { .c = { [0] = 7, } };
// now use
val.u
答案 2 :(得分:0)
由于别名规则导致的这种未定义行为,您只需使用赋值:
i = arr[1];
将uint8_t
值转换为uint32_t
值。