【问题标题】:Strict aliasing rule in array [duplicate]数组中的严格别名规则[重复]
【发布时间】:2015-01-17 11:38:48
【问题描述】:

这段代码是否违反了严格的别名规则:

int main()
{
    short tab[] = {1,2,3,4};
    int* ps = (int*)(&tab[0]);
    int i = *ps;
}

我知道,如果这是相反的方式,那就是违规了

int main()
{
    int tab[] = {1,2,3,4};
    short* ps = (short*)(&tab[0]);
    short s = *ps;
}

【问题讨论】:

  • 您为什么认为这些案例不同?此外,代码实际上并没有访问任何值,您真的是在询问那些确切的代码片段还是更多涉及的内容?
  • AIUI,将任何指针类型转换为任何其他指针类型都是严格的别名违规,除非您在派生类型和基类型之间进行转换,或者在任何指针类型和void* 之间进行转换。
  • @cdhowie 演员阵容并非违规。访问存储的值是。还有比这两个更多的例外。
  • @ShafikYaghmour 是的,我忘了取消引用真正违反规则的指针,我认为这篇文章适用于被视为重复 - 现在一切都清楚了。

标签: c++ strict-aliasing


【解决方案1】:

如果您尝试取消引用转换后的指针,您将在这两种情况下得到未定义的行为。

非正式地,这是因为类型的对齐方式可能不同。

使用联合;使用较长类型和较短类型的数组是一种安全的数据转换方式。

【讨论】:

  • 指针转换不是 UB。这正是reinterpret_cast 所做的。当您尝试通过指针访问存储的值时,会发生严格的别名冲突。
  • 联合技巧通常是编译器支持的。但这仍然是技术上的别名违规。
  • 你确定吗?明天我回来工作时会粘贴一些示例代码。
【解决方案2】:

将指针转换为另一种(任意)指针类型,只要它不是格式错误的,就不会构成违规;但是在取消引用该指针后访问指针值。

你的演员等同于reinterpret_cast, [expr.reinterpret.cast]/7:

一个对象指针可以显式转换为一个对象指针 一种不同的类型。当类型为“指向T1”的纯右值v 是 转换为“pointer to cv T2”类型,结果为static_cast<cv T2*>(static_cast<cv void*>(v)) 如果T1T2 都是标准布局 类型(3.9)和T2的对齐要求不比 T1 的那些,或者任何一个类型都是 void。

【讨论】:

    【解决方案3】:

    当然这违反了严格的别名。代码通过不同类型的指针访问值,它不是char*

    int main()
    {
        short tab[] = {1,2,3,4};
        int* ps = (int*)(&tab[0]);
        *ps = 3;
        if(tab[0] == 1) return 1;
        return 0;
    }
    

    代码允许在那里返回 1。因为对 *ps 的写入是对 int 的写入,并且根据严格的别名规则,int 指针不可能指向 short。因此允许优化器看到tab数组没有被修改,优化出if语句,因为它总是正确的,并重写整个函数以简单地返回1。

    【讨论】:

    • 他究竟在哪里访问这些值?
    • @Columbo:他不是这就是为什么我在代码中添加了一些东西来说明问题。
    猜你喜欢
    • 2015-10-15
    • 2017-02-25
    • 2015-05-31
    • 2013-03-11
    • 2019-01-29
    • 2011-02-15
    • 2018-12-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多