C++ 在最简单的赋值中打破严格的别名规则
在阅读了《理解严格别名》(Understanding Strict Alias)一文后,我看到了违反严格别名规则如何在优化构建中导致意外结果。例如:C++ 在最简单的赋值中打破严格的别名规则,c++,assembly,optimization,strict-aliasing,C++,Assembly,Optimization,Strict Aliasing,在阅读了《理解严格别名》(Understanding Strict Alias)一文后,我看到了违反严格别名规则如何在优化构建中导致意外结果。例如: void test(int* ptr1, float* ptr2); 由于ptr1和ptr2不兼容,编译器假定它们永远不会指向相同的内存。这允许优化代码,如果指针具有相同的值,则会产生意外的结果 然而,在遗留代码中,严格的别名规则在简单赋值中大多被破坏,如intn=0;浮动f=*((浮动*)&n)考虑下面的代码: #include <ios
void test(int* ptr1, float* ptr2);
由于ptr1
和ptr2
不兼容,编译器假定它们永远不会指向相同的内存。这允许优化代码,如果指针具有相同的值,则会产生意外的结果
然而,在遗留代码中,严格的别名规则在简单赋值中大多被破坏,如intn=0;浮动f=*((浮动*)&n)代码>考虑下面的代码:
#include <iostream>
static_assert (sizeof(float) == sizeof(int), "error");
int main(int argc, char *argv[])
{
float f1, f2;
int n = static_cast<int>(argv[1][0] - '0'); // Command argument is "0", so n = 0
memcpy(&f1, &n, sizeof(f1)); // strict-aliasing rule is not broken
f2 = *(reinterpret_cast<float*>(&n)); // strict-aliasing rule is broken
std::cout << f1 << " " << f2 << std::endl; // prints 0 0
return 0;
}
< >我了解如果现代C++编译器会在出错行上给出错误或警告。但如果编译成功,什么优化的汇编代码会产生意外的结果呢
注:
此代码故意违反了严格的别名规则
我知道这是UB
我不想问什么是严格的别名规则,我想知道,在这种特定情况下,违反规则会如何导致UB
一旦你有了UB,任何事情都可能发生
编译器可以在您的程序中执行任何操作
某些编译器在检测到UB时会“删除”UB分支,因此您的程序可能不会显示任何内容(例如)。这就是为什么对UB进行推理是无用的。一旦你有了UB,任何事情都可能发生
编译器可以在您的程序中执行任何操作
某些编译器在检测到UB时会“删除”UB分支,因此您的程序可能不会显示任何内容(例如)。这就是为什么对UB进行推理是无用的。我不明白你在问什么。这并不是说它“能”引起UB,它确实引起UB。你最终的行为是,嗯,没有定义的。您是否在询问特定版本中的特定优化编译器是否以确定性方式处理此问题,以及如何处理?如果是,哪一个编译器?UB不能被“看到”。这是一个语言级别的概念,它规定任何东西都可以从代码中生成,包括一个看似正常工作的二进制文件。从定义上讲,违反规则会导致UB。显示了导致问题的严格别名冲突示例:不同类型的存储在使用long*
的内存副本中移动。(Linux内核过去使用的memcpy
的不安全宏定义,在gcc严格别名破坏它后发生了更改)。@AlexF如果你想从UB中找出差异,这是一个演示。f2
中的附加函数调用在语言上没有区别,但是因为代码有UBf1
和f2
返回不同的结果。我不明白你在问什么。这并不是说它“能”引起UB,它确实引起UB。你最终的行为是,嗯,没有定义的。您是否在询问特定版本中的特定优化编译器是否以确定性方式处理此问题,以及如何处理?如果是,哪一个编译器?UB不能被“看到”。这是一个语言级别的概念,它规定任何东西都可以从代码中生成,包括一个看似正常工作的二进制文件。从定义上讲,违反规则会导致UB。显示了导致问题的严格别名冲突示例:不同类型的存储在使用long*
的内存副本中移动。(Linux内核过去使用的memcpy
的不安全宏定义,在gcc严格别名破坏它后发生了更改)。@AlexF如果你想从UB中找出差异,这是一个演示。根据语言的不同,f2
中的附加函数调用没有区别,但因为代码具有UBf1
和f2
返回不同的结果。
movss xmm0,dword ptr [n]
movss dword ptr [esp+4],xmm0