简体   繁体   English

在最简单的分配中打破严格的混叠规则

[英]Breaking the strict-aliasing rule in the simplest assignment

After reading the Understanding Strict Aliasing article https://cellperformance.beyond3d.com/articles/2006/06/understanding-strict-aliasing.html I see, how breaking the strict-aliasing rules can cause unexpected results in optimized build. 在阅读了理解严格的混叠文章https://cellperformance.beyond3d.com/articles/2006/06/understanding-strict-aliasing.html之后,我看到了,打破严格混叠规则会如何在优化的构建中导致意​​外的结果。 For example: 例如:

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

Since ptr1 and ptr2 are incompatible, compiler assumes that they will never point to the same memory. 由于ptr1ptr2不兼容,因此编译器假定它们永远不会指向同一内存。 This allows to optimize the code, which can give unexpected results, if pointers have the same value. 如果指针具有相同的值,则可以优化代码,从而产生意外结果。

However, in legacy code strict-aliasing rule is mostly broken in simple assignments, like int n = 0; float f = *((float*)&n); 但是,在遗留代码中,严格混叠规则通常在简单的分配中就被破坏,例如int n = 0; float f = *((float*)&n); int n = 0; float f = *((float*)&n); Consider the following code: 考虑以下代码:

#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;
}

I wonder, how it is even possible for C++ compiler to produce an optimized code, which can give different f1 and f2 values, this means, give unexpected result for the code that breaks strict-aliasing rule. 我想知道,C ++编译器甚至有可能生成优化的代码,该代码可以给出不同的f1f2值,这意味着,对于违反严格混淆规则的代码,它给出了意外的结果。

I investigated Assembly code produced by VC++ 2015 compuler in Debug and Release builds (for simplicity, in 32 bit code). 我调查了VC ++ 2015编译器在Debug和Release版本中生成的Assembly代码(为简单起见,使用32位代码)。 In both cases, f2 assignment is converted to 2 movss instructions, like this: 在这两种情况下, f2分配都转换为2条movss指令,如下所示:

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

So, I understand if modern C++ compiler will give an error or warning on the offending line. 因此,我了解现代C ++编译器是否会在违规行上给出错误或警告。 But if compilation is successful, what optimized Assembly code can give an unexpected result? 但是,如果编译成功,哪种优化的Assembly代码会产生意外结果?

Notes: 笔记:

  1. This code intentionally breaks the strict-aliasing rule. 此代码有意违反严格混叠规则。

  2. I know that this is UB. 我知道这是UB。

  3. I don't ask what is the strict-aliasing rule, I want to know, how breaking the rule can cause UB in this specific case. 我不问什么是严格混叠规则,我想知道,在这种特定情况下,违反规则会如何导致UB。

Once you have UB, anything can happen. 一旦有了UB,一切都会发生。

Compiler is allowed to do anything in your program. 编译器可以在程序中执行任何操作。

Some compilers "remove" UB branch when UB is detected, so your program might display nothing for example. 一些编译器在检测到UB时会“删除” UB分支,因此您的程序可能不显示任何内容。 That's why reasoning on UB is useless. 这就是为什么在UB上进行推理没有用的原因。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM