0

我有一些关于联合使用的代码,如下所示:

int main(){

  typedef union{int a;char b[10];float c;}Union;

  Union x,y = {100};
  printf("Union x :%d|   |%s|   |%f \n",x.a,x.b,x.c );
  printf("Union y :%d|   |%s|   |%f \n\n",y.a,y.b,y.c);

  x.a = 50;
  printf("Union x :%d|   |%s|   |%f \n",x.a,x.b,x.c );
  printf("Union y :%d|   |%s|   |%f \n\n",y.a,y.b,y.c);

  strcpy(x.b,"hello");
  printf("Union x :%d|   |%s|   |%f \n",x.a,x.b,x.c );
  printf("Union y :%d|   |%s|   |%f \n\n",y.a,y.b,y.c);

  x.c = 21.50;
  printf("Union x :%d|   |%s|   |%f \n",x.a,x.b,x.c );
  printf("Union y :%d|   |%s|   |%f \n\n",y.a,y.b,y.c);

  return 0;
}

在我编译并执行上面的代码后,我得到了这样的结果:

  Union x :0|     ||    |0.000000 
  Union y :100|   |d|   |0.000000 

  Union x :50|    |2|   |0.000000 
  Union y :100|   |d|   |0.000000 

  Union x :1819043176|     |hello|      |1143141483620823940762435584.000000 
  Union y :100|   |d|   |0.000000 

  Union x :1101791232|   ||    |21.500000 
  Union y :100|   |d|   |0.000000 

不知道为什么yb被初始化为“d”?为什么 xa 和 xc 的值在之后发生了变化?为什么 strcpy(xb,"hello") 不起作用?

4

4 回答 4

3

严格按照标准类型双关语期望在狭窄的情况下是未定义的行为,但实际上许多编译器支持它,例如gcc 手册点here for type- punning和-fstrict-aliasing部分说:

从不同的工会成员那里阅读而不是最近写入的成员(称为“类型双关语”)的做法很常见。即使使用 -fstrict-aliasing,也允许使用类型双关语,前提是通过联合类型访问内存。

如果您打算大量使用类型双关语,我建议您阅读Understanding Strict Aliasing 。

y.b具有该值b,因为联合的所有元素共享内存并且您在ASCII中初始化y为. 这与您修改其他字段时更改的原因相同,包括的情况和取决于您的编译器,这可能未定义或定义良好(在 gcc 的情况下已定义)。100bxstrcpy

为了完整起见,C++ 草案标准部分9.5 联合1段说(强调我的):

在一个联合中,任何时候最多可以有一个非静态数据成员处于活动状态,即任何时候最多可以有一个非静态数据成员的值存储在一个联合中。[注意:为了简化联合的使用,我们做了一个特殊的保证:如果一个标准布局联合包含几个共享一个公共初始序列的标准布局结构(9.2),并且如果这个标准布局联合类型的对象包含标准布局结构之一,允许检查任何标准布局结构成员的公共初始序列;见 9.2。—尾注]联合的大小足以包含其最大的非静态数据成员。每个非静态数据成员都被分配,就好像它是结构的唯一成员一样。

于 2013-10-02T12:49:13.697 回答
2

如果您看到一个ASCII 表,您将看到该值100与字符相同'd'

您必须记住,工会的所有成员共享相同的记忆。这意味着,如果您设置工会的一名成员,所有成员都会改变,而且并不总是可以理解。因此,写入一个成员并从另一个成员读取是未定义的行为。

strcpy(x.b,"hello")确实有效,因为您可以看到工会的所有成员在x您这样做之后都发生了变化。

于 2013-10-02T12:31:50.337 回答
2

您的代码有 UB(未定义的行为);分配给联合的一个成员然后检查另一个成员是非法的(具有相同初始成员的 POD 结构的特殊情况除外)。

读取未初始化的值也是非法的,例如x在赋值之前的任何字段x.a

于 2013-10-02T12:32:04.200 回答
-2

我认为当你说 int a 时,你分配 sizeof(int) ,通常是 32 位。但是当您说 char[10] 时,您分配的是 10 * sizeof(char) 字节!(10 * 4 位)这两个不能相互转换。

于 2013-10-02T12:32:31.437 回答