在C中将字符数组强制转换为int安全吗?

在C中将字符数组强制转换为int安全吗?,c,pointers,casting,portability,C,Pointers,Casting,Portability,想象一下以下情况: 给出了一个由4个uint8_t类型的元素组成的数组,它们逐字节表示32位整数。目标是将整个数组作为32位整数进行寻址 int main( void ) { uint8_t array[4] = { 0, 0, 0, 12 }; uint32_t * ptr = ( uint32_t * )array; printf("%d", *ptr); return 0; } 暂时忘掉endianess吧,它与这个问题无关(我不认为) 现在,C标准指出,

想象一下以下情况:

给出了一个由4个uint8_t类型的元素组成的数组,它们逐字节表示32位整数。目标是将整个数组作为32位整数进行寻址

int main( void )
{
    uint8_t array[4] = { 0, 0, 0, 12 };
    uint32_t * ptr = ( uint32_t * )array;
    printf("%d", *ptr);
    return 0;
}
暂时忘掉endianess吧,它与这个问题无关(我不认为)

现在,C标准指出,将指针强制转换为具有更严格对齐方式的类型是未定义的行为

此处给出了符合和不符合代码的一些示例:

上面的代码在我尝试过的最新GCC和IAR编译器上编译并给出了预期结果

问题是这个代码总体上是否安全

我设想在架构上出现以下情况,其中整数类型是自对齐的。我的逻辑是,由于数组将继承其最严格的类型char的对齐规范,所以它可以放在内存中的任何位置。例如:

Memory | Value | integer can start here
....           
0x20   |       | yes
0x21   | 0     | no   <- array begins, uint32_t ptr
0x22   | 0     | no
0x23   | 0     | no
0x24   | 12    | yes
....
Memory | Value | integer可以从这里开始
....           
0x20 | |是
0x21 | 0 |否
在这种情况下,如果我们取消引用uint32_t指针,我们可能会在某些体系结构上崩溃


这是正确的。不,此代码不安全,并且不可移植,原因与您描述的完全相同。

此代码还违反了严格的别名规则。如果编译器试图优化违反严格别名的代码,则代码可能无法按预期工作。另一个注意事项是,您认为
uint8\t
无符号字符
相同的假设是不可移植的。这也是系统的一个属性。这是未定义的行为,不一定适用于gcc。众所周知,当启用优化时,会为这样的代码创建bug。嵌入式系统编译器通常不会基于严格的别名进行优化,因此即使C标准不能保证IAR也能工作。@chux你说得对,修正了,谢谢你指出这一点out@Frank如果
CHAR\u位!=8
由于不存在
uint8\u t
,因此代码无法编译。数组很可能不会分配到未对齐的地址。只有当您执行
(uint32\u t*)&arr[i]
时,对齐才是一个问题。这里的主要问题是严格的别名规则。@Lundin“可能”在可移植代码是目标时不够好。@Frank编译器没有动机分配未对齐的字符数组,为什么会这样?@Lundin,当然有。压缩结构就是一个简单的例子。具有非常浅堆栈的架构也可能希望这样做。有很多原因。@Frank我在谈论问题中的代码,其中没有提到结构。结构是不同的,因为它们保证在对齐的地址分配,尽管它们的成员可能没有对齐。具有浅堆栈(即8比特)的架构甚至没有对齐。