gpt4 book ai didi

c - 是否有现代目标/编译器的任何示例,其中打破 C 中的严格别名会影响程序结果?

转载 作者:太空宇宙 更新时间:2023-11-04 01:47:40 26 4
gpt4 key购买 nike

有时关于 Stack overflow 的问题和答案建议将指针转换作为一种有效的类型双关方式。它经常被声称这会破坏严格的别名并因此调用未定义行为的说法所拒绝。

现代目标真的关心严格别名吗?在这种情况下,是否有任何程序实例会显示意外行为?

最佳答案

是的,严格别名是一种非常真实的现象,现代编译器经常利用它来执行优化。

考虑以下代码 -

typedef struct
{
char a;
} my_struct;

void foo( int * a, my_struct * b, int count )
{
int i;

for (i=0;i<count;i++)
{
a[i] += b->a;
}
}

当使用 clang 3.8.0-2(这是一个非常现代的编译器)为 X64 目标(这也是一个非常现代的目标)使用命令编译时 -

clang -m64 -S -O2 -std=c11 foo.c -fno-vectorize -fno-unroll-loops

生成以下程序集(简化并采用 AT&T 语法)-

foo:
testl %edx, %edx
jle .LBB0_3
movsbl (%rsi), %eax # Value loaded only once before start of loop
.align 16, 0x90
.LBB0_2:
addl %eax, (%rdi)
addq $4, %rdi
decl %edx
jne .LBB0_2
.LBB0_3:
retq

可以看到 b->a 的值在循环开始之前只加载一次,并添加到 a 中的所有整数。

但是如果这个函数被调用为 -

my_struct a[100];
// initializaion of values in a;
...

foo((int*)a, a, 2); // Breaking strict aliasing

现在很容易看出结果与预期不符。

在使用-fno-strict-aliasing 的较低优化级别,编译器在内部添加指令movsbl (%rsi), %eax循环体。

因此可以公平地得出结论,具有现代编译器的现代架构确实利用了严格的别名,因此不能将指针转换用作类型双关的一种方式。

引用资料:该示例的灵感来自于此 blog post

关于c - 是否有现代目标/编译器的任何示例,其中打破 C 中的严格别名会影响程序结果?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50391984/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com