工会用法和混乱的代码

Union usage and messy code

本文关键字:代码 混乱 用法      更新时间:2023-10-16

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

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 nn",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 nn",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 nn",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 nn",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 

我不知道为什么y.b初始化为"d"?为什么x.a和x.c的值在之后发生了变化? 为什么strcpy(x.b,"hello"(不起作用?

严格按照标准类型双关语期望在狭窄的情况下是未定义的行为,但在实践中许多编译器都支持它,例如 gcc 手册点在这里用于类型双关语和 -fstrict-aliasing 部分是说:

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

如果您打算大量使用类型双关语,我建议您阅读了解严格别名。

y.b的值b,因为联合的所有元素共享内存,并且您使用 ASCIIb 100初始化了y。这与修改一个字段时x其他字段(包括strcpy的情况(发生变化的原因相同,并且根据您的编译器,这可能是未定义的或定义良好的(在 gcc 的情况下,它是定义的(。

为完整起见,C++标准草案第1款9.51款说(强调我的(:

在联合中,最多一个非静态数据成员可以随时

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

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

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

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

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

分配给 x.a 之前读取未初始化的值(例如任何x字段(也是非法的。

我认为当你说int a时,你分配sizeof(int(,通常是32位。但是当你说 char[10] 时,你正在分配 10 * sizeof(char( 字节!!(10 * 4 位(这两者不能互相投射。