转 Struct 和 Union区别 以及 对内存对齐方式的说明
轉(zhuǎn)載地址:http://blog.csdn.net/firefly_2002/article/details/7954458
?
一、Struct 和 Union有下列區(qū)別:
1.在存儲(chǔ)多個(gè)成員信息時(shí),編譯器會(huì)自動(dòng)給struct第個(gè)成員分配存儲(chǔ)空間,struct 可以存儲(chǔ)多個(gè)成員信息,而Union每個(gè)成員會(huì)用同一個(gè)存儲(chǔ)空間,只能存儲(chǔ)最后一個(gè)成員的信息。
2.都是由多個(gè)不同的數(shù)據(jù)類型成員組成,但在任何同一時(shí)刻,Union只存放了一個(gè)被先選中的成員,而結(jié)構(gòu)體的所有成員都存在。
3.對(duì)于Union的不同成員賦值,將會(huì)對(duì)其他成員重寫(xiě),原來(lái)成員的值就不存在了,而對(duì)于struct 的不同成員賦值 是互不影響的。
注:在很多地方需要對(duì)結(jié)構(gòu)體的成員變量進(jìn)行修改。只是部分成員變量,那么就不能用聯(lián)合體Union,因?yàn)?/span>Union的所有成員變量占一個(gè)內(nèi)存。eg:在鏈表中對(duì)個(gè)別數(shù)值域進(jìn)行賦值就必須用struct.
?
二、實(shí)例說(shuō)明
struct?簡(jiǎn)單來(lái)說(shuō)就是一些相互關(guān)聯(lián)的元素的集合,說(shuō)是集合,其實(shí)它們?cè)趦?nèi)存中的存放是有先后順序的,并且每個(gè)元素都有自己的內(nèi)存空間。那么按照什么順序存放的呢?其實(shí)就是按你聲明的變量順序來(lái)存放的,下面先看一個(gè)例子:
struct sTest
{
int a;? //sizeof(int) = 4
char b;? //sizeof(char) = 1
shot c;?//sizeof(shot) = 2
}x;
所以在內(nèi)存中至少占用?4+1+2 = 7 byte。然而實(shí)際中占用的內(nèi)存并不是7 byte,這就涉及到了字節(jié)對(duì)齊方式。
?
union?的不同之處就在于,它所有的元素共享同一內(nèi)存單元,且分配給union的內(nèi)存size?由類型最大的元素?size?來(lái)確定,如下的內(nèi)存就為一個(gè)double?類型?size?:
union uTest
{
int a;?? //sizeof(int) = 4
double b;? //sizeof(double) = 8
char c;? //sizeof(char) = 1
}x;
所以分配的內(nèi)存?size?就是8 byte。
既然是內(nèi)存共享,理所當(dāng)然地,它不能同時(shí)存放多個(gè)成員的值,而只能存放其中的一個(gè)值,就是最后賦予它的值,如:
x.a = 3; x.b = 4.5; x.c = ‘A’;
這樣你只看到x.c = ‘A’,而其它已經(jīng)被覆蓋掉,失去了意義。
eg:??Sample聯(lián)合只包含其中某一個(gè)成員,要么是index,要么是price。
union Sample {
?? int index;
?? double price; };
若???Sample ss; ss.index =10;// 從今往后只能使用ss.index
若???Sample ss; ss.price=14.25;// 從今往后只能使用ss.price
?在union的使用中,如果給其中某個(gè)成員賦值,然后使用另一個(gè)成員,是未定義行為,后果自負(fù)。
struct成員是互相獨(dú)立的,一個(gè)struct包含所有成員。
C/C++ code
struct Example
{
int index;
double price;
};
Example結(jié)構(gòu)包含兩個(gè)成員,修改index不會(huì)對(duì)price產(chǎn)生影響,反之亦然。
union的成員共享內(nèi)存空間,一個(gè)union只包含其中某一個(gè)成員。
說(shuō)到這里,大家應(yīng)該已經(jīng)明白兩者最關(guān)鍵的區(qū)別了吧,無(wú)非就在于內(nèi)存單元的分配和使用。然而要靈活地使用struct和union?還是存在許多小技巧的,比如:元素的相關(guān)性不強(qiáng)時(shí),完全是可以使用union,從而節(jié)省內(nèi)存size;?struct和union還可以相互嵌套。
?
三、內(nèi)存對(duì)齊方式
union u
{
double a;
int b;
};
union u2
{
char a[13];
int b;
};
union u3
{
char a[13];
char b;
};
cout<<sizeof(u)<<endl; // 8
cout<<sizeof(u2)<<endl; // 16
cout<<sizeof(u3)<<endl; // 13
? 都知道union的大小取決于它所有的成員中,占用空間最大的一個(gè)成員的大小。所以對(duì)于u來(lái)說(shuō),大小就是最大的double類型成員a了,所以sizeof(u)=sizeof(double)=8。但是對(duì)于u2和u3,最大的空間都是char[13]類型的數(shù)組,為什么u3的大小是13,而u2是16呢?關(guān)鍵在于u2中的成員int b。由于int類型成員的存在,使u2的對(duì)齊方式變成4,也就是說(shuō),u2的大小必須在4的對(duì)界上,所以占用的空間變成了16(最接近13的對(duì)界)。
結(jié)論:復(fù)合數(shù)據(jù)類型,如union,struct,class的對(duì)齊方式為成員中對(duì)齊方式最大的成員的對(duì)齊方式。
順便提一下CPU對(duì)界問(wèn)題,32的C++采用8位對(duì)界來(lái)提高運(yùn)行速度,所以編譯器會(huì)盡量把數(shù)據(jù)放在它的對(duì)界上以提高內(nèi)存命中率。對(duì)界是可以更改的,使用#pragma pack(x)宏可以改變編譯器的對(duì)界方式,默認(rèn)是8。C++固有類型的對(duì)界取編譯器對(duì)界方式與自身大小中較小的一個(gè)。例如,指定編譯器按2對(duì)界,int類型的大小是4,則int的對(duì)界為2和4中較小的2。在默認(rèn)的對(duì)界方式下,因?yàn)閹缀?/span>所有的數(shù)據(jù)類型都不大于默認(rèn)的對(duì)界方式8(除了long double),所以所有的固有類型的對(duì)界方式可以認(rèn)為就是類型自身的大小。更改一下上面的程序:
#pragma pack(2)
union u2
{
char a[13];
int b;
};
union u3
{
char a[13];
char b;
};
#pragma pack(8)
cout<<sizeof(u2)<<endl; // 14 由于手動(dòng)更改對(duì)界方式為2,所以int的對(duì)界也變成了2,u2的對(duì)界取成員中最大的對(duì)界,也是2了,所以此時(shí)sizeof(u2)=14。
cout<<sizeof(u3)<<endl; // 13 ,char的對(duì)界為1
? 結(jié)論:C++固有類型的對(duì)界取編譯器對(duì)界方式與自身大小中較小的一個(gè)。
?
struct的sizeof問(wèn)題
因?yàn)閷?duì)齊問(wèn)題使結(jié)構(gòu)體的sizeof變得比較復(fù)雜,看下面的例子:(默認(rèn)對(duì)齊方式下)
struct s1
{
char a;
double b;
int c;
char d;
};
struct s2
{
char a;
char b;
int c;
double d;
};
cout<<sizeof(s1)<<endl; // 24
cout<<sizeof(s2)<<endl; // 16
?同樣是兩個(gè)char類型,一個(gè)int類型,一個(gè)double類型,但是因?yàn)閷?duì)界問(wèn)題,導(dǎo)致他們的大小不同。計(jì)算結(jié)構(gòu)體大小可以采用元素?cái)[放法,我舉例子說(shuō)明一下:首先,CPU判斷結(jié)構(gòu)體的對(duì)界,根據(jù)上一節(jié)的結(jié)論,s1和s2的對(duì)界都取最大的元素類型,也就是double類型的對(duì)界8。然后開(kāi)始擺放每個(gè)元素。
對(duì)于s1,首先把a放到8的對(duì)界,假定是0,此時(shí)下一個(gè)空閑的地址是1,但是下一個(gè)元素d是double類型,要放到8的對(duì)界上,離1最接近的地址是8了,所以d被放在了8,此時(shí)下一個(gè)空閑地址變成了16,下一個(gè)元素c的對(duì)界是4,16可以滿足,所以c放在了16,此時(shí)下一個(gè)空閑地址變成了20,下一個(gè)元素d需要對(duì)界1,也正好落在對(duì)界上,所以d放在了20,結(jié)構(gòu)體在地址21處結(jié)束。由于s1的大小需要是8的倍數(shù),所以21-23的空間被保留,s1的大小變成了24。
對(duì)于s2,首先把a放到8的對(duì)界,假定是0,此時(shí)下一個(gè)空閑地址是1,下一個(gè)元素的對(duì)界也是1,所以b擺放在1,下一個(gè)空閑地址變成了2;下一個(gè)元素c的對(duì)界是4,所以取離2最近的地址4擺放c,下一個(gè)空閑地址變成了8,下一個(gè)元素d的對(duì)界是8,所以d擺放在8,所有元素?cái)[放完畢,結(jié)構(gòu)體在15處結(jié)束,占用總空間為16,正好是8的倍數(shù)。
?
特例:
#include<stdio.h>
union{
int i;
char x[2]; }a;
void main()
{
a.x[0]=10;
a.x[1]=1;
printf("%d",a.i);
?}
在聯(lián)合體a中定義了兩種數(shù)據(jù)類型,字符數(shù)組x以及整形變量i.其中整形變量是16位的,數(shù)組大小為2的字符數(shù)組為8X2=16位。如此一來(lái),編譯器便會(huì)為聯(lián)合體a在內(nèi)存中開(kāi)辟一個(gè)16位的空間,這個(gè)空間里存儲(chǔ)聯(lián)合體的數(shù)據(jù),但是這個(gè)空間只有16位,它既是整形變量的數(shù)據(jù),也是字符數(shù)組的數(shù)據(jù)。如果你的程序從字符數(shù)組的角度解析這個(gè)空間,那么它就是兩個(gè)字符,如果你的程序從整型的角度解析這個(gè)空間,那么它就是一個(gè)整數(shù)。??
? 以你的程序?yàn)槔?#xff0c;現(xiàn)在已經(jīng)開(kāi)辟了一個(gè)16位的空間,然后我們假定現(xiàn)在空間還沒(méi)有被賦值,為:??
? 00000000 00000000??
? 那么在運(yùn)行完代碼??
? a.x[0] = 10;??
? a.x[1] = 1;??
? 之后,16位的空間變?yōu)?#xff1a;??
? 00000110 00000001??
? 然后程序運(yùn)行??
? printf("%d",a.i);??
? 就是把聯(lián)合體a當(dāng)成一個(gè)整數(shù)來(lái)解析,而不是字符串?dāng)?shù)組。那么這樣一來(lái),程序就把這16位變成了一個(gè)完整的整數(shù):??
? (00000001 00000110)二進(jìn)制 = (266)十進(jìn)制?
轉(zhuǎn)載于:https://www.cnblogs.com/webber1992/p/5950199.html
總結(jié)
以上是生活随笔為你收集整理的转 Struct 和 Union区别 以及 对内存对齐方式的说明的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: DBCP连接池介绍
- 下一篇: POJ 3265 DP