结构与联盟的区别

有什么好的例子来区分一个struct和一个union ? 基本上我知道struct使用其成员的所有内存,并且union使用最大的成员内存空间。 有没有其他操作系统级别的差异?

有了联盟,你只能使用其中一个元素,因为它们都存储在同一个地方。 当你想存储可能是几种types之一的东西时,这会很有用。 另一方面,结构对于每个元素都有独立的内存位置,并且它们都可以一次使用。

为了给出一个具体的例子,我刚刚在一个Scheme解释器上工作,我基本上把Scheme数据types覆盖到C数据types上。 这包括在一个结构体中存储一个枚举值,并指定一个联合体来存储该值。

 union foo { int a; // can't use both a and b at once char b; } foo; struct bar { int a; // can use both a and b simultaneously char b; } bar; union foo x; xa = 3; // OK xb = 'c'; // NO! this affects the value of xa! struct bar y; ya = 3; // OK yb = 'c'; // OK 

编辑:如果你想知道把xb设置为'c'是怎样改变xa的值的,从技术上来说这是不确定的。 在大多数现代机器上,char是1个字节,而int是4个字节,所以给xb赋值'c'也给出xa的第一个字节相同的值:

 union foo x; xa = 3; xb = 'c'; printf("%i, %i\n", xa, xb); 

版画

 99, 99 

为什么这两个值是一样的? 因为int 3的最后3个字节都是零,所以它也被读为99.如果我们为xa加上一个更大的数字,你会发现情况并非总是如此:

 union foo x; xa = 387439; xb = 'c'; printf("%i, %i\n", xa, xb); 

版画

 387427, 99 

为了更仔细地看看实际的内存值,我们设置并输出hex值:

 union foo x; xa = 0xDEADBEEF; xb = 0x22; printf("%x, %x\n", xa, xb); 

版画

 deadbe22, 22 

您可以清楚地看到0x22覆盖0xEF的位置。

在C中,int中的字节顺序没有定义。 这个程序在我的Mac上用0x22覆盖了0xEF,但是还有其他的平台会覆盖0xDE,因为构成int的字节的顺序是相反的。 因此,在编写程序时,不应该依赖覆盖联合中特定数据的行为,因为这不是可移植的。

有关字节顺序的更多信息,请查看字节顺序 。

下面是简短的答案:结构是一个logging结构:结构中的每个元素分配新的空间。 所以,像一个结构

 struct foobarbazquux_t { int foo; long bar; double baz; long double quux; } 

为每个实例分配至less(sizeof(int)+sizeof(long)+sizeof(double)+sizeof(long double))字节的内存。 (“至less”,因为架构alignment约束可能会强制编译器填充结构。)

另一方面,

 union foobarbazquux_u { int foo; long bar; double baz; long double quux; } 

分配一块内存,并给它四个别名。 因此sizeof(union foobarbazquux_u) ≥ max((sizeof(int),sizeof(long),sizeof(double),sizeof(long double)) ,同样可能会有一些alignment的加法。

有没有什么好的例子来区分“结构”和“联盟”?

一个虚构的通信协议

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

在这个虚构的协议中,已经规定,基于“消息types”,头中的以下位置将是请求号或四字符代码,但不是两者。 简而言之,工会允许相同的存储位置表示多个数据types,在这种情况下,保证您只需要在任何时间存储一种types的数据。

工会在很大程度上是基于C作为系统编程语言的底层细节,其中“重叠”存储位置有时以这种方式使用。 有时可以使用联合来节省内存,只要你有一个数据结构,一次只能保存几种types中的一种。

一般来说,操作系统并不关心或了解结构和联合 – 它们都是简单的内存块。 结构是一个内存块,它存储了几个数据对象,这些对象不重叠。 联合是一个存储多个数据对象的内存块,但只有最大的存储空间,因此只能存储一个数据对象。

正如你已经在你的问题中所述, unionstruct的主要区别是union成员覆盖彼此的内存,以便联合的sizeof是一个,而struct成员是一个接一个地布置(与可选的填充在之间)。 还有一个联盟足够容纳所有成员,并且有一个适合所有成员的联盟。 所以我们假设int只能存储在2个字节的地址中,而且是2个字节的宽度,long只能存储在4个字节的地址中,长度是4个字节。 以下工会

 union test { int a; long b; }; 

可以具有4的sizeof ,并且alignment要求为4.联合和结构都可以在末尾具有填充,但不在其开始处。 写入结构只会改变写入的成员的值。 写给工会会员将使所有其他会员的价值无效。 如果您以前没有写过,则无法访问它们,否则行为是不确定的。 海湾合作委员会提供了一个扩展名,你可以从工会成员那里读到,即使你最近没有写过。 对于操作系统来说,用户程序是写入联合体还是写入结构并不重要。 这实际上只是编译器的一个问题。

union和struct的另一个重要属性是,它们允许指向它们的指针可以指向任何成员的types 。 所以下面是有效的:

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

some_test_pointer可以指向int*bool* 。 如果你把一个types为test的地址int* ,它实际上会指向它的第一个成员a 。 对于一个工会也是如此。 因此,因为工会总是有正确的路线,你可以使用工会来指出某种types的有效:

 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标准所述:

对象的存储值只能由具有以下types之一的左值expression式访问:

  • 与对象的有效types兼容的types
  • 在其成员中包括上述types之一的聚合或联合types

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

union在一些情况下是有用的。 union可以是一个非常低级别的操作工具,比如编写内核的设备驱动程序。

一个例子是解剖一个float通过使用一个struct与位域和float 。 我在float保存了一个数字,之后我可以通过这个struct访问float特定部分。 这个例子展示了如何使用union来以不同的angular度来查看数据。

 #include <stdio.h> union foo { struct float_guts { unsigned int fraction : 23; unsigned int exponent : 8; unsigned int sign : 1; } fg; float f; }; void print_float(float f) { union foo ff; ff.f = f; printf("%f: %d 0x%X 0x%X\n", f, ff.fg.sign, ff.fg.exponent, ff.fg.fraction); } int main(){ print_float(0.15625); return 0; } 

看看维基百科的单精度描述。 我用这个例子和那个魔法数字0.15625。


union也可以用来实现一个具有多种select的代数数据types。 我在O'Sullivan,Stewart和Goerzen的“真实世界Haskell”一书中find了一个例子。 在“歧视的联盟”部分查看。

干杯!

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

但所有的区别在于内存的使用需求。 联盟的最佳用法可以在我们使用信号的unix进程中看到。 就像一个进程一次只能处理一个信号一样。 所以一般的声明是:

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

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

总之,如果你知道你一次访问任何一个成员,就应该select联盟。

非技术上来说意味着:

假设:chair =内存块,people =variables

结构 :如果有三个人可以相应地坐在他们的大小的椅子上。

联盟 :如果有3人只有一把椅子坐在那里,所有需要坐在同一把椅子上。

从技术上讲是指:

下面提到的scheme深入了解了结构和联合。

 struct MAIN_STRUCT { UINT64 bufferaddr; union { UINT32 data; struct INNER_STRUCT{ UINT16 length; UINT8 cso; UINT8 cmd; } flags; } data1; }; 

总共MAIN_STRUCT大小= sizeof(UINT64)为bufferaddr + sizeof(UNIT32)为union + 32位填充(取决于处理器体系结构)= 128位。 对于结构,所有的成员都连续地获取内存块。

Union获得最大大小成员(这里是它的32位)的一个内存块。 在union内部还有一个结构体(INNER_STRUCT),它的成员得到一个总大小为32位(16 + 8 + 8)的内存块。 在联合中,可以访问INNER_STRUCT(32位)成员数据(32位)。

union ”和“ struct ”是C语言的结构。 说到它们之间的“操作系统级别”差异是不恰当的,因为如果你使用一个或另一个关键字, 编译器会产生不同的代码。

一个结构体将分配其中所有元素的总大小。

一个工会只分配尽可能多的内存,因为它最大的成员需要。

你拥有它,就是这样。 但是,基本上,工会有什么意义呢?

您可以放置​​在不同types的相同位置内容。 你必须知道你存储在联合中的types(通常你把它放在一个带有types标签的struct )。

为什么这很重要? 不是真正的空间收益。 是的,你可以获得一些或填充,但这不是主要的一点。

这是为了types安全,它使您能够进行某种“dynamicinput”:编译器知道您的内容可能具有不同的含义,以及在运行时如何解释它的确切含义。 如果你有一个可以指向不同types的指针,你必须使用联合,否则你的代码可能是不正确的,因为别名问题(编译器说自己“哦,只有这个指针可以指向这种types,所以我可以优化那些访问……“,坏事情可能会发生)。

工会的使用经常在需要专门types的谈话时使用。 了解工会的用处。 c / c标准库没有定义专门devise用于将短整数写入文件的函数。 使用fwrite()会导致简单操作的额外开销。 然而,使用联合可以轻松创build一个函数,将一个短整数的二进制文件一次写入一个字节的文件。 我假设短整数是2个字节长

这个例子:

 #include<stdio.h> union pw { short int i; char ch[2]; }; int putw(short int num, FILE *fp); int main (void) { FILE *fp; fp fopen("test.tmp", "wb "); putw(1000, fp); /* write the value 1000 as an integer*/ fclose(fp); return 0; } int putw(short int num, FILE *fp) { pw word; word.i = num; putc(word.c[0] , fp); return putc(word.c[1] , fp); } 

虽然putw()我用短整数调用,它是可以使用putc()和fwrite()。 但我想举一个例子来说明如何使用一个工会

结构是不同数据types的集合,其中不同types的数据可以驻留在其中,并且每个数据types都有自己的内存块

我们通常使用联合,当我们确定只有一个variables会被一次性使用,并且你想要充分利用当前的内存,因为它只能得到一个等于最大types的内存块。

 struct emp { char x;//1 byte float y; //4 byte } e; 

它得到的总内存=> 5个字节

 union emp { char x;//1 byte float y; //4 byte } e; 

它获得的总内存= 4字节

编写下面给出的字节sortingfunction时,工会来得方便。 结构是不可能的。

 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. 

Wonder Union不同于结构,Union与其他结构不同:它重新定义了相同的内存,同时结构一个接一个地定义,没有重叠或重新定义。