3
enum Enums { k1, k2, k3, k4 };

union MYUnion { 
    struct U{ 
         char P;
    }u;

    struct U0 { 
        char state; 
    } u0; 

    struct U1 { 
        Enums e; 
        char c; 
        int v1; 
    } u1; 

    struct U2 { 
        Enums e; 
        char c; 
        int v1; 
        int v2; 
    } u2; 

    struct U3 { 
        Enums e; 
        unsigned int i; 
        char c; 
    } u3; 

    struct U4 { 
        Enums e;
        unsigned int i; 
        char c; 
        int v1; 
    } u4; 

    struct U5 { 
        Enums e; 
        unsigned int i; 
        char c; 
        int v1; 
        int v2; 
    } u5; 
} myUnion

我对 C++ 中的 Union 的整个想法感到非常困惑。这个“myUnion”在内存中是什么样子的?我知道数据共享相同的内存块,但是如何?“myUnion”的大小是多少?如果是“u5”的大小,那么这块内存中的数据是如何分配的??

4

5 回答 5

1
  1. 联合体的大小是联合体中最大事物的大小。
  2. 联合的布局是您最后存储的任何内容。

因此,在您的最后一个联合中,如果您存储到.i,然后存储到.eint 的第一个字节,将被枚举值覆盖(假设sizeof (enum)在您的环境中为 1)。

工会就像:

void * p = malloc(sizeof(biggest_item))
Enums *ep = (Enums *)e;
unsigned int * ip = (unsigned int *)p;
char *cp = (char *)p;

分配给*ep*ip*cp的工作就像工会一样。

于 2009-11-22T02:27:07.390 回答
1

正如 Murali 所说,联合的规模将是参与联合的最大结构的规模。

该应用程序将为最大块分配足够的字节。内存映射的工作方式如下:

考虑以下:

union Foo
{
  struct A
  {
    int x;
    unsigned char y;
    unsigned char z;

  }
  struct B
  {
    unsigned char a;
    unsigned char b;
    unsigned char c;
    unsigned char d;
    unsigned char e;
  }
}

在这种情况下,假设 int 是 32 位(取决于您的目标平台),a、b、c 和 d 提供对构成整数 X 的字节的访问。写入 A 将覆盖 x、b 的第一个字节将覆盖 x 的第二个字节,依此类推。

相反,向 X 写入值会影响 a、b、c 和 d。

无符号字符 y 和 e 占用相同的空间(同样,取决于 int 是 32 位的事实),因此 .y 和 .e 是彼此的有效别名。

unsigned char Az 不与结构 B 的任何元素重叠,因此它实际上不受 B 更改的影响。

这里的重点是联合结构的元素占用相同的内存。通过允许您使用不同的数据类型,不同的结构提供了读取和写入相同内存的不同方法。

于 2009-11-22T02:27:36.373 回答
1

你的困惑是对的!我很困惑......让我们先看一些简单的东西,然后再继续讨论您拥有的更复杂的示例。

第一工会基础。联合只是意味着当您创建联合类型的变量时,底层组件(在下面的 i 和 f 示例中)在内存中确实重叠。它有时让您将该内存视为一个 int,有时将该内存视为一个浮点数。这自然会很讨厌,你真的必须知道你在做什么。

union AUnion
{
   int i;
   float f;
}; // assumes an int is 32 bits

AUnion aUnion;
aUnion.i = 0;
printf("%f", aUnion.f);

在上面的代码中,会打印出什么?要理解该问题的答案,您必须了解整数和浮点数在内存中的表示方式。两者都占用 32 位内存。然而,这两种类型的记忆是如何解释的。当我设置 aUnion.i = 0 时,我说的是“将一个 0 整数写入 aUnion”。一个 0'd 整数,它恰好对应于将所有 32 位设置为 0。现在,当我们打印 aUnion.f 时,我们说“将 aUnion 视为真正的 32 位浮点数,并打印它出来了!然后计算机将所有这些底层位视为浮点数而不是 int 的一部分。计算机知道如何将任何随机的 32 位串视为浮点数,因为它知道浮点数是怎样的格式化为二进制

现在来处理一些更复杂的联合代码:

enum Enums { k1, k2, k3, k4 };

union MYUnion { 
struct U{ 
     char P;
}u;

struct U0 { 
    char state; 
} u0; 

struct U1 { 
    Enums e; 
    char c; 
    int v1; 
} u1; 

所有这些结构都以与上面的 int 和 float 相同的方式重叠。现在,如果我们假设枚举映射到一个 int。然后我们可以根据枚举的规则将枚举映射到底层内存中的 int 值:

 enum Enums { k1/*0*/, k2/*1*/, k3/*2*/, k4/*3*/ };

那么我们所拥有的是

union MYUnion { 
struct U{ 
     char P;
}u;

struct U0 { 
    char state; 
} u0; 

struct U1 { 
    int e; 
    char c; 
    int v1; 
} u1; 

你有一个非常奇怪的结合,因为如果你这样做

MyUnion m;
m.u.P = 'h'

当您稍后访问枚举(这很可能是引擎盖下的 int )时,它将被读取为无效值。这是因为 P 只是 1 个字节,而 int 是 4 个字节。当作为枚举读取时,你会得到奇怪的结果。

我强烈建议您解雇负责此代码的人。

于 2009-11-22T02:35:46.153 回答
0

可能是因为联合不是一个很棒的功能。它们可能对您受到极大限制的内存共享很有用。或不可移植的内存技巧(写入一种大小的变量并从另一种读取)。或用于模拟漂亮的标记工会。

标记联合模式的工作原理是这样的。

enum mytags { FULL_TIME_WORKER, PART_TIMER, CONTRACTOR}

struct worker_t {
    enum mytags tag,
    union {
        struct full_time_worker_t full_time_wroker,
         struct part_time_worker_t part_time_worker,
         struct contractor_t contractor }
    }
}


bool person_can_do_x(worker_t w)
{
    switch(workers.tag)
    {
    case FULL_TIME_WORKER:
    ...
    case PART_TIMER:
    ...
    case CONTRACTOR:
       ...w.contractor.....
    default:
        return true
    }
}
于 2011-06-05T13:26:08.747 回答
0

并且它取决于目标 CPU 的内存模型(大 - 小)字节序等,以了解内存块的外观,但通常每个结构将在同一区域开始相同的地址和布局 -如果你知道它会做什么,那么它很有用,否则一枪打到脚上。

于 2009-11-22T02:27:59.960 回答