有什么好的例子可以说明结构体和联合体的区别吗? 基本上我知道struct使用了它成员的所有内存,而union使用了最大的成员内存空间。还有其他操作系统级别的差异吗?


当前回答

“union”和“struct”是C语言的构造。谈论它们之间的“操作系统级别”差异是不合适的,因为如果您使用一个或另一个关键字,则是编译器产生不同的代码。

其他回答

是的,struct和union之间的主要区别和你说的一样。 Struct使用其成员的所有内存,union使用最大的成员内存空间。

但所有的区别在于使用内存的需要。 在unix的进程中可以看到联合的最佳使用,在那里我们使用信号。 比如一个进程一次只能作用于一个信号。 所以一般声明是:

union SIGSELECT
{
  SIGNAL_1 signal1;
  SIGNAL_2 signal2;
  .....
};

在这种情况下,进程只使用所有信号中最高的内存。 但如果在这种情况下使用struct,内存使用量将是所有信号的总和。 有很大的不同。

总之,如果您知道一次访问任何一个成员,则应该选择Union。

As you already state in your question, the main difference between union and struct is that union members overlay the memory of each other so that the sizeof of a union is the one , while struct members are laid out one after each other (with optional padding in between). Also an union is large enough to contain all its members, and have an alignment that fits all its members. So let's say int can only be stored at 2 byte addresses and is 2 bytes wide, and long can only be stored at 4 byte addresses and is 4 bytes long. The following union

union test {
    int a;
    long b;
}; 

could have a sizeof of 4, and an alignment requirement of 4. Both an union and a struct can have padding at the end, but not at their beginning. Writing to a struct changes only the value of the member written to. Writing to a member of an union will render the value of all other members invalid. You cannot access them if you haven't written to them before, otherwise the behavior is undefined. GCC provides as an extension that you can actually read from members of an union, even though you haven't written to them most recently. For an Operation System, it doesn't have to matter whether a user program writes to an union or to a structure. This actually is only an issue of the compiler.

union和struct的另一个重要属性是,它们允许指向它们的指针可以指向其任何成员的类型。因此,以下是有效的:

struct test {
    int a;
    double b;
} * some_test_pointer;

Some_test_pointer可以指向int*或double*。如果将一个test类型的地址转换为int*,它将指向它的第一个成员,实际上是a。工会也是如此。因此,因为联合将始终具有正确的对齐方式,您可以使用联合来使指向某些类型的指针有效:

union a {
    int a;
    double b;
};

这个联合实际上可以指向int型和double型:

union a * v = (union a*)some_int_pointer;
*some_int_pointer = 5;
v->a = 10;
return *some_int_pointer;    

实际上是有效的,正如C99标准所述:

对象的存储值只能由具有以下类型之一的左值表达式访问: 与对象的有效类型兼容的类型 ... 在其成员中包含上述类型之一的聚合或联合类型

编译器不会优化出v->a = 10;因为它可能会影响*some_int_pointer的值(该函数将返回10而不是5)。

有什么好的例子可以说明“结构体”和“联合体”之间的区别吗?

一种假想的通信协议

struct packetheader {
   int sourceaddress;
   int destaddress;
   int messagetype;
   union request {
       char fourcc[4];
       int requestnumber;
   };
};

在这个假想的协议中,已经指定了基于“消息类型”的消息头中的下面位置要么是请求号,要么是四个字符的代码,但不是两者都是。简而言之,联合允许相同的存储位置表示多个数据类型,可以保证您在任何时候只希望存储其中一种类型的数据。

联合在很大程度上是基于C作为系统编程语言的传统的低级细节,其中“重叠”存储位置有时以这种方式使用。如果数据结构一次只保存几种类型中的一种,则有时可以使用联合来节省内存。

一般来说,操作系统不关心或不知道结构体和并体——它们都只是内存块。struct是存储多个数据对象的内存块,这些对象不重叠。联合是存储多个数据对象的内存块,但只能存储其中最大的一个,因此在任何时候只能存储其中一个数据对象。

你拥有它,仅此而已。 那么,工会的意义是什么呢?

您可以在相同的位置中放入不同类型的内容。你必须知道你在联合中存储的东西的类型(所以你经常把它放在一个带有type标签的结构体中…)

为什么这很重要?并不是为了获得空间。是的,你可以获得一些位或做一些填充,但这已经不是重点了。

这是为了类型安全,它允许你做某种“动态类型”:编译器知道你的内容可能有不同的含义,你如何解释它的确切含义取决于你在运行时。如果你有一个指针可以指向不同的类型,你必须使用联合,否则你的代码可能会因为别名问题而不正确(编译器会对自己说“哦,只有这个指针可以指向这种类型,所以我可以优化这些访问……”,糟糕的事情可能会发生)。

在编写下面给出的字节排序函数时,联合非常方便。这在结构体中是不可能的。

int main(int argc, char **argv) {
    union {
        short   s;
        char    c[sizeof(short)];
    } un;

    un.s = 0x0102;

    if (sizeof(short) == 2) {
        if (un.c[0] == 1 && un.c[1] == 2)
            printf("big-endian\n");
        else if (un.c[0] == 2 && un.c[1] == 1)
            printf("little-endian\n");
        else
            printf("unknown\n");
    } else
        printf("sizeof(short) = %d\n", sizeof(short));

    exit(0);
}
// Program from Unix Network Programming Vol. 1 by Stevens.