在最简单的分配中违反严格混叠规则

时间:2018-11-07 10:07:53

标签: c++ assembly optimization strict-aliasing

阅读了解严格的混叠文章https://cellperformance.beyond3d.com/articles/2006/06/understanding-strict-aliasing.html之后,我了解到,打破严格混叠规则会如何在优化的构建中导致意​​外结果。例如:

void test(int* ptr1, float* ptr2);

由于ptr1ptr2不兼容,因此编译器假定它们永远不会指向相同的内存。如果指针具有相同的值,则可以优化代码,从而产生意外结果。

但是,在旧版代码中,严格混叠规则在简单的分配中大都被打破,例如int n = 0; float f = *((float*)&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 ++编译器甚至有可能生成优化的代码,该代码可以给出不同的f1f2值,这意味着,如果代码违反严格,别名规则。

我研究了VC ++ 2015编译器在Debug和Release版本中生成的汇编代码(为简单起见,使用32位代码)。在这两种情况下,f2分配都将转换为2条movss指令,如下所示:

movss       xmm0,dword ptr [n]  
movss       dword ptr [esp+4],xmm0  

因此,我了解现代C ++编译器是否会在违规行上给出错误或警告。但是,如果编译成功,哪种优化的Assembly代码会产生意外结果?

注意:

  1. 此代码有意违反了严格的混叠规则。

  2. 我知道这是UB。

  3. 我不问什么是严格混叠规则,我想知道,在这种特定情况下违反规则会导致UB。

1 个答案:

答案 0 :(得分:2)

一旦有了UB,一切都会发生。

允许编译器在程序中执行任何操作。

某些编译器在检测到UB时会“删除” UB分支,因此您的程序可能不显示任何内容。这就是为什么在UB上进行推理没有用的原因。