C ++与联合的未定义行为

时间:2013-06-24 10:31:27

标签: c++

只是阅读一些匿名结构以及它是如何不标准的,并且它的一些一般用例是未定义的行为......

这是基本情况:

struct Point {
    union {
       struct {
           float x, y;
       };
       float v[2];
    };
};

所以写入x然后从v [0]读取将是未定义的,因为你会期望它们是相同的,但可能不是这样。

不确定这是否属于同一类型的标准联盟...

union{ float a; float b; };

是否未定义写入a然后从b读取?

也就是说,标准是否有关于数组的二进制表示和相同类型的顺序变量的说法。

3 个答案:

答案 0 :(得分:6)

标准说从联盟中的任何元素读取其他元素 比写的最后一个是未定义的行为。在理论上, 编译器可以生成以某种方式跟踪的代码 读取和写入,并在您违反时触发信号 规则(即使两者是同一类型)。编译器也可以 使用这个事实进行某种优化:如果你写信给a (或x),可以假设您没有阅读b(或v[0]) 在优化时。

实际上,我所知道的每个编译器都支持这个, if union 是清晰可见的,有很多案例(大多数?,全部?) 如果工会不可见,即使合法使用也会失败 (例如:

union  U { int i; float f; };

int f( int* pi, int* pf ) { int r = *pi; *pf = 3.14159; return r; }

//  ...
U u;
u.i = 1;
std::cout << f( &u.i, &u.f );

我实际上已经看到这个用g ++失败了,尽管根据 标准,这是完全合法的。)

此外,即使编译器支持写入Point::x和 从Point::v[0]读取,无法保证Point::y 并且Point::v[1]甚至具有相同的物理地址。

答案 1 :(得分:0)

标准要求在联合中“[e] ach数据成员被分配,就好像它是结构的唯一成员一样。” (9.5)

它还要求struct { float x, y; }float v[2]必须具有相同的内部表示(9.2),因此您可以安全地重新解释转换为另一个

将这两条规则结合在一起可以保证您描述的union能够正常运行,只要它真正写入内存即可。但是,因为标准只要求写入的最后一个数据成员有效,所以如果联合仅用作局部变量,理论上可能会使实现失败。然而,如果真的发生了,我会感到惊讶。

答案 2 :(得分:-5)

我不明白为什么你使用了浮动v [2];

点结构的简单并集可以定义为:

union{

struct {

    float a;
    float b;
};

} Point;

您可以在unioin中访问值:

Point.a = 10.5; 

point.b = 12.2; //example