严格的别名和覆盖继承 [英] Strict aliasing and overlay inheritance

查看:104
本文介绍了严格的别名和覆盖继承的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑以下代码示例:

#include <stdio.h>

typedef struct A A;

struct A {
   int x;
   int y;
};

typedef struct B B;

struct B {
   int x;
   int y;
   int z;
};

int main()
{
    B b = {1,2,3};
    A *ap = (A*)&b;

    *ap = (A){100,200};      //a clear http://port70.net/~nsz/c/c11/n1570.html#6.5p7 violation

    ap->x = 10;  ap->y = 20; //lvalues of types int and int at the right addrresses, ergo correct ?

    printf("%d %d %d\n", b.x, b.y, b.z);
}

我以前认为将B *强制转换为A *并使用A *操纵B *对象之类的行为是严格的别名冲突. 但是后来我意识到该标准实际上只要求:

I used to think that something like casting B* to A* and using A* to manipulate the B* object was a strict aliasing violation. But then I realized the standard really only requires that:

一个对象的存储值只能由左值访问 具有以下类型之一的表达式:1)兼容类型 带有对象的有效类型,(...)

An object shall have its stored value accessed only by an lvalue expression that has one of the following types: 1) a type compatible with the effective type of the object, (...)

和诸如ap->x之类的表达式确实具有正确的类型和地址,并且ap的类型在那里实际上并不重要(或者是吗?).在我看来,这暗示着这种覆盖继承是正确的,只要未对整个子结构进行操作即可.

and expressions such as ap->x do have the correct type and address, and the type of ap shouldn't really matter there (or does it?). This would, in my mind, imply that this type of overlay inheritance is correct as long as the substructure isn't manipulated as a whole.

这种解释是否存在缺陷或表面上与标准作者的意图背道而驰?

Is this interpretation flawed or ostensibly at odds with what the authors of the standard intended?

推荐答案

带有*ap =的行是严格的别名冲突:类型为B的对象是使用类型为A的左值表达式编写的.

The line with *ap = is a strict aliasing violation: an object of type B is written using an lvalue expression of type A.

假设该行不存在,我们移到了ap->x = 10; ap->y = 20;.在这种情况下,使用类型为int的左值写入类型为int的对象.

Supposing that line was not present, and we moved onto ap->x = 10; ap->y = 20;. In this case an lvalue of type int is used to write objects of type int.

对于这是否是严格的混叠违规存在分歧.我认为该标准的文字没有,但是其他人(包括gcc和clang开发人员)认为ap->x表示已访问*ap.多数人认为标准对严格混叠的定义过于模糊,需要改进.

There is disagreement about whether this is a strict aliasing violation or not. I think that the letter of the Standard says that it is not, but others (including gcc and clang developers) consider ap->x as implying that *ap was accessed. Most agree that the standard's definition of strict aliasing is too vague and needs improvement.

使用您的结构定义对代码进行采样:

Sample code using your struct definitions:

void f(A* ap, B* bp)
{
  ap->x = 213;
  ++bp->x;
  ap->x = 213;
  ++bp->x;
}

int main()
{
   B b = { 0 };
   f( (A *)&b, &b );
   printf("%d\n", b.x);
}

对我来说,这在-O2处输出214,在-O3处输出2,带有gcc. 在gcc 6.3上Godbolt上生成的程序集是:

For me this outputs 214 at -O2, and 2 at -O3 , with gcc. The generated assembly on godbolt for gcc 6.3 was:

f:
    movl    (%rsi), %eax
    movl    $213, (%rdi)
    addl    $2, %eax
    movl    %eax, (%rsi)
    ret

这表明编译器已将函数重新排列为:

which shows that the compiler has rearranged the function to:

int temp = bp->x + 2;
ap->x = 213;
bp->x = temp;

,因此编译器必须考虑ap->x可能不是bp->x的别名.

and therefore the compiler must be considering that ap->x may not alias bp->x.

这篇关于严格的别名和覆盖继承的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆