存储多个值的联盟

时间:2016-08-19 18:51:01

标签: c++ floating-point char double unions

以下是代码:

#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会引发错误吗?

3 个答案:

答案 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的不同顺序,因为系统对它们的解释不同。例如,intfloat

当您保存到联盟的某个字段时,它会采用与您指定的对应的0和1的正确顺序,并将其存储在那里。如果将15保存到int字段,并将其作为浮点数读取,则会得到一个完全不同的数字,因为您已经强制它以不同于预期的顺序读取数字。

这一切都归结为@GManNickG在评论中所说的,这是未定义的行为。那个0和1的序列仍然是一个数字,而不是你认为的那个。读取数字并用它进行计算是完全有效的。这就是为什么使用union的东西通常有一个第二个字段,通常是一个enum,与union分开定义,指定保存在哪个类型中,以便你知道在程序的另一部分稍后使用它时要读哪个。