c++ - 违反严格别名,即使没有任何转换?

标签 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* 可以作为 union 的 int 成员的别名。还有第 3 行,因为任何可以影响一个 union 成员 (u.s) 的东西都可以影响同一 union 的另一个成员。但是在预测 *i 时,它没有意识到第 3 行会影响 *i 处的 int 左值。

这个理论看起来合理吗?

我觉得这个例子很有趣,因为我没有在其中进行任何转换。我设法通过进行任何转换来打破严格别名。

最佳答案

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

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

标准语:

N4140 §9.5[class.union]/1

In a union, at most one of the non-static data members can be active at any time, that is, the value of at most one of the non-static data members can be stored in a union at any time.

关于c++ - 违反严格别名,即使没有任何转换?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39757246/

相关文章:

c++ - Const C++ 函数中的赋值

c - C 中的灵活数组和取消引用类型双关指针错误

c - 仅写入动态分配的存储 block 的一部分是否设置了整个 block 的有效类型?

c99 - 只要我们确定不创建别名,将 uint8_t* 转换为 uint32_t* 或 uint64_t* 是否在 C99 中定义良好?

c - 严格的别名和覆盖继承

c++ - C++ (GCC) 中的 C99 严格别名规则

C++ int i 未在 for() 中声明

c++ - 在 C++ 中删除韩语字符串中的子字符串

c++ - 如何在 C++ 中正确删除链表的节点

c++ - 使用可变参数宏生成数组