【问题标题】:Union storing multiple values联合存储多个值
【发布时间】:2016-12-27 00:31:57
【问题描述】:

代码如下:

#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(声明为双精度的值)。当我尝试输出 mytypes.c 时,它会打印一个空白方块(表示字符未正确显示)。

根据我对联合的理解,它不应该只包含单一类型的单一值吗?如果这是真的,那它不是一个值为 41.7341 的浮点数,所以调用它作为 double 或 char 会引发错误吗?

【问题讨论】:

  • "抛出错误" -> 这是 C++。 :) 你得到未定义的行为。
  • 请注意,访问联合的非活动部分是未定义的行为。
  • 如果您想出错,请使用变体类型,例如boost::variant

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


【解决方案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

【讨论】:

    【解决方案2】:

    我将对您的类型做出一些假设,以便为解释提供具体数字。我假设:char = 1 字节,int 和 float = 4 字节,double = 8 字节。

    现在,它们保存在内存中的相同位置。通常,如果在结构中声明一个 int 和一个 float,int 将占用前 4 个字节,float 将占用后 4 个字节。但是保存的数据都是 0 和 1,将相同的数字保存为 int 或 float 将具有不同的 0 和 1 顺序,因为它们对系统的解释不同。例如intfloat

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

    这一切都归结为@GManNickG 在他们的评论中所说的,这是未定义的行为。 0 和 1 的序列仍然是一个数字,只是不是你认为的那个数字。将其作为数字读入并用它进行计算是完全有效的。这就是为什么使用联合的东西通常有第二个字段,通常是一个枚举,独立于联合定义,指定保存在其中的类型,以便您知道当程序的另一部分稍后使用它时要读取哪个。

    【讨论】:

      【解决方案3】:

      联合的目的是将许多类型分配到同一内存区域。所以联合有内存,你可以根据你在联合中声明的任何类型来表示该内存。

      如果您将 char 显式转换为 double 或反之,您会收到错误,不!联合基本上是类型转换,使用的内存更少。

      【讨论】:

      • 显式转换将执行转换。工会没有。
      猜你喜欢
      • 2022-11-10
      • 1970-01-01
      • 2010-09-21
      • 2012-03-31
      • 2013-10-12
      • 2015-05-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多