以下是代码:
#include <iostream>
union mytypes_t {
char c;
int i;
float f;
double d;
} mytypes;
int main() {
mytypes.c = 'z';
mytypes.d = 4.13021;
mytypes.f = 41.7341;
cout << mytypes.d << endl;
return 0;
}
程序输出4.13021(声明为double的值)。当我尝试输出mytypes.c
时,会打印一个空白方块(表示字符未正确显示)。
根据我对联盟的理解,它不应该只保留单一类型的单一值吗?如果这是真的,它不是一个值为41.7341的浮点数,因此将其称为double或char会引发错误吗?
答案 0 :(得分:1)
如其他答案中所述,所有工会成员占用相同的存储空间。您始终可以将内存解释为基本类型,但结果可能是意外的。
我滔滔不绝地用代码打印出一些十六进制的细节。您可以看到内存将随着每个连续值的分配而改变。当指定浮点数时,双精度不会完全改变,因此输出值接近原始值。这只是类型大小和硬件架构的副作用。
作为旁注,使用cout打印十六进制字符为什么会这么痛苦。
#include <iomanip>
#include <iostream>
#include <string.h>
union mytypes_t {
unsigned char a[8];
char c;
int i;
float f;
double d;
} mytypes;
int main() {
memset(&mytypes,0,8);
std::cout << "Size of the union is: " << sizeof(mytypes) << std::endl;
mytypes.c = 'z';
for(int i=0;i<8;i++)
printf("%02x ", mytypes.a[i]);
printf("\n");
mytypes.d = 4.13021;
for(int i=0;i<8;i++)
printf("%02x ", mytypes.a[i]);
printf("\n");
mytypes.f = 41.7341;
for(int i=0;i<8;i++)
printf("%02x ",mytypes.a[i]);
printf("\n");
std::cout << mytypes.c << std::endl;
std::cout << mytypes.d << std::endl;
std::cout << mytypes.f << std::endl;
return 0;
}
Size of the union is: 8
7a 00 00 00 00 00 00 00 // The char is one byte
da 72 2e c5 55 85 10 40 // The double is eight bytes
b8 ef 26 42 55 85 10 40 // The float is the left most four bytes
�
4.13021
41.7341
答案 1 :(得分:0)
联合的目的是将多种类型分配给相同的内存区域。因此,union具有内存,您可以根据您在union中声明的任何类型来表示该内存。
如果你明确地将一个char转换为double,反之亦然,那么你会得到一个错误,没有。联合基本上是类型转换,使用的内存较少。
答案 2 :(得分:0)
我将对你的类型做一些假设,只是为了解释这个问题的具体数字。我假设:char = 1个字节,int和float = 4个字节,double = 8个字节。
现在,它们被保存在内存中的相同位置。通常,如果在结构中声明int和float,则int将占用前4个字节,而float将占用第2个4个字节。但保存的数据全部为0和1,并且保存与int或float相同的数字将具有0和1的不同顺序,因为系统对它们的解释不同。例如,int,float。
当您保存到联盟的某个字段时,它会采用与您指定的对应的0和1的正确顺序,并将其存储在那里。如果将15保存到int字段,并将其作为浮点数读取,则会得到一个完全不同的数字,因为您已经强制它以不同于预期的顺序读取数字。
这一切都归结为@GManNickG在评论中所说的,这是未定义的行为。那个0和1的序列仍然是一个数字,而不是你认为的那个。读取数字并用它进行计算是完全有效的。这就是为什么使用union的东西通常有一个第二个字段,通常是一个enum,与union分开定义,指定保存在哪个类型中,以便你知道在程序的另一部分稍后使用它时要读哪个。