结构和联合的区别

有没有什么好的例子来说明structunion之间的区别? 基本上我知道struct使用其成员的所有内存,而union使用最大的成员内存空间。还有其他操作系统级别的差异吗?< / p >

383111 次浏览

结构分配其中所有元素的总大小。

一个联合只分配它最大的成员所需要的内存。

对于联合,您只应该使用其中一个元素,因为它们都存储在同一个位置。这在您想要存储可能是几种类型之一的内容时非常有用。另一方面,结构体的每个元素都有单独的内存位置,并且它们都可以一次使用。

为了给出它们使用的一个具体例子,我不久前正在研究一个Scheme解释器,我实际上是将Scheme数据类型覆盖到C数据类型上。这涉及到在一个结构体中存储一个指明值类型的枚举和一个用于存储该值的联合。

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;
x.a = 3; // OK
x.b = 'c'; // NO! this affects the value of x.a!


struct bar y;
y.a = 3; // OK
y.b = 'c'; // OK

编辑:如果你想知道将x.b设置为'c'会改变x.a的值,从技术上讲它是未定义的。在大多数现代机器上,char是1字节,int是4字节,所以给x.b的值'c'也给x.a的第一个字节相同的值:

union foo x;
x.a = 3;
x.b = 'c';
printf("%i, %i\n", x.a, x.b);

打印

99, 99

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

union foo x;
x.a = 387439;
x.b = 'c';
printf("%i, %i\n", x.a, x.b);

打印

387427, 99

为了更仔细地查看实际的内存值,让我们设置并打印十六进制的值:

union foo x;
x.a = 0xDEADBEEF;
x.b = 0x22;
printf("%x, %x\n", x.a, x.b);

打印

deadbe22, 22

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

在我的Mac上,这个程序用0x22覆盖了0xEF,但在其他平台上,它会覆盖0xDE,因为组成int的字节的顺序颠倒了。因此,在编写程序时,永远不要依赖于覆盖联合中特定数据的行为,因为它是不可移植的。

有关字节排序的更多阅读,请查看字节顺序

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

正如你在你的问题中已经说过的,unionstruct之间的主要区别是union成员相互覆盖内存,因此联合的sizeof是1,而struct成员是一个接一个地布局(中间有可选的填充)。另外,一个联合要大到足以容纳它的所有成员,并且要有适合所有成员的对齐。所以让我们说int只能存储在2个字节地址,并且是2个字节宽,而long只能存储在4个字节地址,并且是4个字节长。以下联盟

union test {
int a;
long b;
};

可以有sizeof为4,对齐要求为4。联合和结构都可以在结尾有填充,但不能在开头有填充。写入结构只会改变写入的成员的值。写信给联合的一个成员将使所有其他成员的值无效。如果之前没有写过,就不能访问它们,否则行为是未定义的。GCC提供了一个扩展,即使您最近没有给工会成员写信,您也可以从工会成员那里实际读取。对于操作系统,用户程序是写入联合还是写入结构并不重要。这实际上只是编译器的问题。

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)。

你拥有它,就这样。 那么,工会的意义是什么呢?< / p >

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

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

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

简单的回答是:结构体是一个记录结构体:结构体中的每个元素分配新的空间。一个结构体

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

为每个实例分配至少(sizeof(int)+sizeof(long)+sizeof(double)+sizeof(long double))字节的内存。(“至少”是因为架构对齐约束可能迫使编译器填充结构。)

另一方面,

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)),同样有可能添加一些对齐。

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

一种假想的通信协议

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

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

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

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

是的,struct和union之间的主要区别和你说的一样。 Struct使用其成员的所有内存,union使用最大的成员内存空间 但是所有的区别都在于对内存的使用需求。 在unix的进程中可以看到联合的最佳使用,在那里我们使用信号。 比如一个进程一次只能作用于一个信号。 所以一般的声明是:

union SIGSELECT
{
SIGNAL_1 signal1;
SIGNAL_2 signal2;
.....
};
在这种情况下,进程只使用所有信号中最高的内存。 但如果在这种情况下使用struct,内存使用量将是所有信号的总和。 有很大不同

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

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

其中一个例子是通过使用带有位字段的structunionfloat来解析float数。我在float中保存了一个数字,之后我可以通过该struct访问float的特定部分。这个例子展示了如何使用union来从不同的角度查看数据。

#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也可用于实现具有多个替代的代数数据类型。我在O'Sullivan, Stewart和Goerzen的《Real World Haskell》一书中找到了一个例子。 在受歧视的工会部分查看它

干杯!

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

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.
结构是不同数据类型的集合,不同类型的数据可以驻留在其中

当我们确定一次只使用其中一个变量,并且希望充分利用当前内存时,我们通常使用联合,因为它只获得一个等于最大类型的内存块。

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

它获得的总内存:=>5字节。

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

它获得的总内存:4字节。

union的使用 当需要特殊类型的对话时,联合经常被使用。 来了解联合的用处。c/c标准库没有定义专门为将短整数写入文件而设计的函数。使用fwrite()会导致简单操作的开销过大。然而,使用联合可以很容易地创建一个函数,该函数将一个短整数的二进制每次一个字节写入文件。我假设短整数长度为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()。但是我想展示一个例子来说明如何使用联合

从技术上讲,非指:

假设:椅子=记忆块,人=变量

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

联盟:如果有3个人只有一个椅子将在那里坐,所有人都需要使用同一把椅子当他们想坐。

技术上讲是指:

下面提到的程序对结构和联合进行了深入研究。

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

MAIN_STRUCT size =sizeof(UINT64) for bufferaddr + sizeof(UNIT32) for union + 32 bit for padding(取决于处理器架构)= 128 bits。 对于结构,所有成员连续获取内存块

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

Union不同于struct,因为Union在其他的上面重复:它重新定义同一个内存,而struct一个接一个地定义,没有重叠或重定义。

结构和联合的区别是什么?

简单的回答是:区别在于内存分配。 解释: 在结构中,将为结构内部的所有成员创建内存空间。 在联合内存空间将只为需要最大内存空间的成员创建。 考虑以下代码:

struct s_tag
{
int a;
long int b;
} x;


union u_tag
{
int a;
long int b;
} y;

这里在struct和union内部有两个成员:int和long int。在32位操作系统中,int的内存空间为:4字节,long int的内存空间为:8。

因此,对于struct, 4+8=12个字节将被创建,而对于union,将创建8个字节

代码示例:

#include<stdio.h>
struct s_tag
{
int a;
long int b;
} x;
union u_tag
{
int a;
long int b;
} y;
int main()
{
printf("Memory allocation for structure = %d", sizeof(x));
printf("\nMemory allocation for union = %d", sizeof(y));
return 0;
}

裁判:http://www.codingpractise.com/home/c-programming/structure-and-union/

当我们需要对具有一组独立属性的事物进行建模时,建议使用结构;当一个实体具有多种形式且一次只能以一种形式存在时,建议使用联合。

让我们看看它们可以应用的两个地方

您需要存储和更新汽车的值。为了做到这一点,我们需要记录汽车的所有属性,如型号、里程、价格和燃料类型。这些值总是存在于一辆车中,它们不依赖于其他值。 因此,我们需要一种数据类型,它不仅存储所有属性,而且还确保它们的正确更新。这些类型的任务可以使用结构来完成

struct car{
char model[];
int mileage;
int price;
char fuel_type[];
};

组织需要从大量客户那里收集您的数据进行付款验证。现在,为了数据完整性和客户安全,一个组织被指示从一个人那里获得最少的详细信息。 这些详细信息可以是您的PAN号码或帐户号码或选民身份证。现在,因为我们需要收集这些细节中的任何一个,同时也要节省内存,我们可以在这里使用联合。它将只保存提供给它的单个值

union verification_details{
char account_number[10];
char PAN[10];
char voter_id[10];
};

我发现下面的文章解释得很好:结构和联合的区别

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

下面是来自嵌入式系统应用的真实例子。它只使用union,但它清楚地显示了union的功能。

I2C通信协议的写函数使用union类型,用于数据存储,从传递给它的数组中检索数据。

union data
{
uint32_t packet;
uint8_t  packetbyte[4];
} txdata;

通过指针传递给write函数的数组包含一个字节大小的元素。在for循环中,这些字节分四步逐一提取,并存储到txdata.packetbyte成员的各个元素中。

循环结束后,txdata.packet保存了4个字节的数据,这些数据被连续存储到txdata并集中。作为通过通信总线发送数据的最后一步,txdata.packet被写入32位缓冲区,在被写入后,该缓冲区启动写序列。然后在开始执行next for循环之前通过txdata.packet = 0重置内容。

通过这种方式,I2C主机可以重新传输32位数据包,直到发送通过的输入数据并终止写入功能。