简体   繁体   English

当其他成员设置为新值时,C union成员给出特定/错误值。 为什么此输出在C中的以下代码中?

[英]C union member gives particular/wrong value when other member is set to a new value. Why is this output in following code in C?

#include <stdio.h>
int main()
{
  union Data
  {
    char str[20];    
    int i;
    float f;
  }data;

  data.i=20;
  data.f=220.5;
  printf("%d\n",(data.i));

  return 0;
}

The output is:1130135552. 输出为:1130135552。 I used gcc complier on Ubuntu 16.04 LTS. 我在Ubuntu 16.04 LTS上使用了gcc complier。

Can someone explain the output? 有人可以解释输出吗?

The members data.i and data.f occupy same memory location, so output should be 220. But why output is 1130135552? 成员data.idata.f占用相同的内存位置,因此输出应该是220.但为什么输出是1130135552?

According to C11 Section 6.5.2.3 Footnote 95 根据C11第6.5.2.3节脚注95

If the member used to read the contents of a union object is not the same as the member last used to store a value in the object, the appropriate part of the object representation of the value is reinterpreted as an object representation in the new type as described in 6.2.6 (a process sometimes called ''type punning''). 如果用于读取union对象内容的成员与上次用于在对象中存储值的成员不同,则将值的对象表示的相应部分重新解释为新类型中的对象表示形式在6.2.6中描述(一个过程有时被称为''punning'')。 This might be a trap representation. 这可能是陷阱表示。

The specific output depends on the layout of the members in memory and the type. 具体输出取决于内存中成员的布局和类型。 Therefore, when you store data.f and then access data.i , the bit patterns in the memory of data.f is reinterpreted as an integer. 因此,当您存储data.f然后访问data.idata.f内存中的位模式将重新解释为整数。

Note the following: 请注意以下事项:

int a = 1;
float b = 1;

These two although may seem to have a similar layout on memory, but they are stored differently. 这两个虽然看起来在内存上看起来有类似的布局,但它们的存储方式不同。 In the case of integer, it will be generally stored in a two's complement format (although it can be other formats as well), and a floating point will be generally stored using the IEEE754 format (although it can be different). 在整数的情况下,它通常以二进制补码格式存储(尽管它也可以是其他格式),并且通常使用IEEE754格式存储浮点(尽管它可以是不同的)。 Therefore, trying to interpret a number stored using IEEE754 as integer will get you something totally different. 因此,尝试将使用IEEE754存储的数字解释为整数将获得完全不同的东西。

Also, not that, according to C11 Section 6.2.6.1 Paragraph 7 而且,根据C11第6.2.6.1节第7段,不是这样

When a value is stored in a member of an object of union type, the bytes of the object representation that do not correspond to that member but do correspond to other members take unspecified values. 当值存储在union类型的对象的成员中时,对象表示的字节与该成员不对应但与其他成员对应的字节采用未指定的值。

Therefore, if you assign to a member of an object of a union, then the values in the bytes of other location which is not used by the member which you assigned will have unspecified values. 因此,如果您指定了union的对象的成员,那么您指定的成员未使用的其他位置的字节中的值将具有未指定的值。

As you are already aware that union shares memory location between the members inside. 正如您已经知道union在内部成员之间共享内存位置。 In case of union compiler allocated the memory equal to the max size of the member and use the same memory for all the members. 如果union编译器分配的内存等于成员的最大大小,则对所有成员使用相同的内存。

Hence when you execute data.f=220.5; 因此,当您执行data.f=220.5; , shared memory location between i and f holding data.i=20; if保持data.i=20;之间的共享内存位置data.i=20; got overwritten to a new value (220.5) with binary representation as follows : 被覆盖为具有二进制表示的新值(220.5),如下所示:

在此输入图像描述

Now again, when this value is read as a signed integer int it will be interpreted without conversion as 1130135552 in decimal representation. 现在再次,当该值被读取为有符号整数int ,它将被解释为没有转换为十进制表示中的1130135552 Hence you are getting 1130135552 . 因此,你得到1130135552

Further if you want to use all members of union, then struct is the answer. 此外,如果你想使用union的所有成员,那么struct就是答案。

struct Data
{
    char str[20];
    int i;
    float f;
} data;

data.i=20;
data.f=220.5;
printf("%d\n",data.i);

For more information on union and struct Please refer the following from Difference between Structure and Union : 有关unionstruct更多信息请参阅以下结构和联合之间的区别 在此输入图像描述

If I may, let's restrict this answer to the case where sizeof(float) is the same as sizeof(int) , that float is a single precision IEEE754 type, and int is a 2's complement type. 如果可以的话,让我们将这个答案限制在sizeof(float)sizeof(int)相同的情况下, float是单精度IEEE754类型, int是2的补码类型。 If you don't understand what I'm saying here, ignore this paragraph for now: it's here in an attempt to make this answer watertight; 如果你不明白我在这里说的话,现在就忽略这一段:它试图让这个答案变得无懈可击; a bit like the legalese in a financial contract. 有点像金融合约中的法律术语。

A float is a remarkable type capable of representing numbers in a large range with a remarkable amount of precision. float是一种非凡的类型,能够以极高的精度表示大范围内的数字。 The format it uses internally to achieve this is aa complex one. 它内部用于实现此目的的格式是一个复杂的格式 If you want to know more, see https://en.wikipedia.org/wiki/IEEE_754 . 如果您想了解更多信息,请访问https://en.wikipedia.org/wiki/IEEE_754

When you write data.f = 220.5; 当你写data.f = 220.5; , you are setting the first sizeof(float) bytes in your union to have the memory associated with the constant 220.5f . ,您要在union中设置第一个sizeof(float)字节,以使内存与常量220.5f相关联。

But an int uses an entirely different format. 但是int使用完全不同的格式。 When you output the int member of the union, you recover the int with value 1130135552 . 当您输出union的int成员时,您将使用值1130135552恢复int This is related to the 220.5f in that both have exactly the same pattern of bits. 这与220.5f有关,因为两者具有完全相同的位模式。

The char str[20]; char str[20]; in your union is a red herring. 在你的union是一个红鲱鱼。

data.i and data.f share the same memory, but the interpretation of a value is different in integer and float. data.idata.f共享相同的内存,但整数和浮点值的解释是不同的。

With a float converter you get following values: 使用浮点转换器,您将获得以下值:

220.5 in float means: 
sign: 1
exponent: 134 
mantissa: 1.72265625 encoded as :6062080

binary representation:0 10000110 10111001000000000000000  (sign, exponent, mant.)
hex representation: 0x435c8000
dezimal representation:1130135552  (the value you get!!)

As explicited by phoxis , the standard declares that the value is unspecified. 正如phoxis所解释的那样 ,标准声明该值未指定。

However, pragmatically, this is a good example of binary interpretation. 但是,实际上,这是二进制解释的一个很好的例子。

I assume the width for an int and float on your platform is 32 bits, and a floating-point value follows the IEEE 754 representation . 我假设平台上的intfloat的宽度是32位,浮点值遵循IEEE 754表示

What happens here: 这里发生了什么:

data.f=220.5;

This statement writes the floating-point value as binary 0100 0011 0101 1100 1000 0000 0000 0000 in the memory location of data , overwriting any previous value. 此语句将浮点值写为二进制0100 0011 0101 1100 1000 0000 0000 0000data的内存位置,覆盖任何先前的值。

The next time the value is accessed is when read as an integer: data.i member access in your printf call. 下次访问该值时,读取为整数: printf调用中的data.i成员访问权限。 The value read, in binary, is still 0100 0011 0101 1100 1000 0000 0000 0000 , and as a signed integer, this is interpreted without conversion as 1130135552 . 以二进制形式读取的值仍然是0100 0011 0101 1100 1000 0000 0000 0000 ,并且作为有符号整数,这被解释为不转换为1130135552

If you want the value to be converted, you have to read the value as a floating-point (using data.f ) and convert it to an integer value with a cast: 如果要转换值,则必须将值读取为浮点(使用data.f )并将其转换为带有data.f转换的整数值:

printf("%d\n",(int)(data.f));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM