将数组指针强制转换为另一种类型会为不同的编译器优化提供不同的输出



我在C++中尝试reinterpret_cast,但后来发现它不一致。它为不同的优化级别提供了不同的输出。然后我尝试了它的C版本,它再次给出了错误的输出。

这是C代码:

#include <stdio.h>
#include <stdlib.h>
int main(int argc, char const *argv[]) {
unsigned long long* arr = (unsigned long long*)malloc(16);
arr[0] = 0x300000061;
arr[1] = 9;
int* casted = (int*)(arr);
for (int i = 0; i < 3; ++i)
printf("%dn", casted[i]);
return 0;
}

请注意它投射指针的int* casted = (int*)(arr);。当在for循环中转换为char*并将3增加到12时,它给出了我期望的输出。

带有O1-O3标志的输出:

0
0
0

无任何O标志的输出:

97
3
9

带字符输出(带或不带优化(:

97
0
0
0
3
0
0
0
9
0
0
0

第二个输出是我所期望的。这种指针投射是未定义的行为还是编译器错误?

我使用WSL-gcc编译器。

编辑:感谢您的快速回复。有没有一种方法可以编写asm函数来获得所需的输出?我知道我可以用memcpy((代替,但我需要在一个无法轻易解释的特定问题中使用它,所以我宁愿不使用。

与呈现的C程序对话:

第二个输出是我所期望的。这种指针投射是未定义的行为还是编译器错误?

强制转换具有定义良好的行为,但通过生成的int *读取数据违反了严格的混叠规则(C17第6.5/7段(。这会产生未定义的行为。另一方面,允许通过char *读取任何对象的表示,因此变化是可以的(至少在C中(。

在不同优化级别上可观察到的行为变化是UB的常见症状之一,尤其是由于违反严格的混叠规则而引起的UB。

据我所知,类似的情况也适用于C++:您可以使用reinterpret_castunsigned long long *转换为int *,但UB的结果是试图取消对结果指针的引用。

最新更新