违反严格别名,即使没有任何演员?

时间:2016-09-28 20:40:13

标签: c++ strict-aliasing

我想我真的在问:别名是“传递”吗?如果编译器知道A可能是别名B,而B可能是别名C,那么肯定它应该记住A可能因此别名C.也许这个“明显的”传递逻辑不是必需的吗?

一个例子,为了清楚起见。对我来说,最有趣的例子是严格别名问题:

// g++    -fstrict-aliasing -std=c++11 -O2
#include <iostream>

union
{   
    int i;
    short s;
} u;
int     * i = &u.i;

int main()
{   

    u.i = 1; // line 1
    *i += 1; // line 2

    short   & s =  u.s;
    s += 100; // line 3

    std::cout
        << " *i\t" <<  *i << std::endl // prints 2
        << "u.i\t" << u.i << std::endl // prints 101
        ;

    return 0;
}

g ++ 5.3.0,在x86_64(但不是clang 3.5.0)上给出了上面的输出,其中*iu.i给出了不同的数字。但是他们应该提供完全相同的数字,因为i定义为int * i = &u.i;i不会更改。

我有一个理论:当'预测'u.i的值时,编译器会询问哪些行可能会影响u.i的内容。这显然包括第1行。第2行,因为int*可以为联盟的int成员添加别名。第3行也是如此,因为任何可能影响一个联盟成员(u.s)的东西都会影响同一联盟的另一个成员。但是在预测*i时,它没有意识到第3行会影响int的{​​{1}}左值。

这个理论看起来合理吗?

我觉得这个例子很有趣,因为我没有任何演员。我设法通过任何演员来打破严格别名。

2 个答案:

答案 0 :(得分:5)

在C ++中未定义从union的非活动成员读取。 (它在C99和C11中是合法的。)

所以,总而言之,编译器不需要假设/记住任何东西。

Standardese:

  N4140§9.5[class.union] / 1      

在联合中,最多一个非静态数据成员可以随时处于活动状态,也就是说,任何时候最多一个非静态数据成员的值都可以存储在一个联合中。

答案 1 :(得分:1)

只允许从最后用C ++写入的union成员中读取。

只允许在类似的&#39;之间使用工会外的别名。类型(详情请参阅this Q/A)和char / unsigned char。只允许通过char / unsigned char为其他类型设置别名,但不允许通过其他类型对char / unsigned char进行别名。如果允许后者,那么所有对象都必须被视为可能别名任何其他对象,因为它们可能是传递别名的#39;就像你通过char / unsigned char描述一样。

但是因为情况并非如此,编译器可以安全地假设只有类似“&#39;”的对象。类型和char / unsigned char互为别名。