Struct 和 Union有下列區別
轉自:http://blog.csdn.net/firefly_2002/article/details/7954458
一、Struct 和 Union有下列區別
1.在儲存多個成員資訊時,編譯器會自動給struct第個成員分配儲存空間,struct 可以儲存多個成員資訊,而Union每個成員會用同一個儲存空間,只能儲存最後一個成員的資訊。
2.都是由多個不同的資料型別成員組成,但在任何同一時刻,Union只存放了一個被先選中的成員,而結構體的所有成員都存在。
3.對於Union的不同成員賦值,將會對其他成員重寫,原來成員的值就不存在了,而對於struct 的不同成員賦值 是互不影響的。
注:在很多地方需要對結構體的成員變數進行修改。只是部分成員變數,那麼就不能用聯合體Union,因為Union的所有成員變數佔一個記憶體。eg:在連結串列中對個別數值域進行賦值就必須用struct.
二、例項說明
struct 簡單來說就是一些相互關聯的元素的集合,說是集合,其實它們在記憶體中的存放是有先後順序的,並且每個元素都有自己的記憶體空間。那麼按照什麼順序存放的呢?其實就是按你宣告的變數順序來存放的,下面先看一個例子:
struct sTest
{
int a; //sizeof(int) = 4
char b; //sizeof(char) = 1
shot c; //sizeof(shot) = 2
}x;
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
所以在記憶體中至少佔用 4+1+2 = 7 byte。然而實際中佔用的記憶體並不是7 byte,這就涉及到了位元組對齊方式。
union 的不同之處就在於,它所有的元素共享同一記憶體單元,且分配給union的記憶體size 由型別最大的元素 size 來確定,如下的記憶體就為一個double 型別 size :
union uTest
{
int a; //sizeof(int) = 4
double b; //sizeof(double) = 8
char c; //sizeof(char) = 1
}x;
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
所以分配的記憶體 size 就是8 byte。
既然是記憶體共享,理所當然地,它不能同時存放多個成員的值,而只能存放其中的一個值,就是最後賦予它的值,如:
x.a = 3; x.b = 4.5; x.c = ‘A’;
這樣你只看到x.c = ‘A’,而其它已經被覆蓋掉,失去了意義。
eg: Sample聯合只包含其中某一個成員,要麼是index,要麼是price。
union Sample {
int index;
double price;
};
- 1
- 2
- 3
- 4
若
Sample ss; ss.index =10;//從今往後只能使用ss.index
若
Sample ss; ss.price=14.25;//從今往後只能使用ss.price
在union的使用中,如果給其中某個成員賦值,然後使用另一個成員,是未定義行為,後果自負。
struct成員是互相獨立的,一個struct包含所有成員。
struct Example
{
int index;
double price;
};
- 1
- 2
- 3
- 4
- 5
Example結構包含兩個成員,修改index不會對price產生影響,反之亦然。
union的成員共享記憶體空間,一個union只包含其中某一個成員。
說到這裡,大家應該已經明白兩者最關鍵的區別了吧,無非就在於記憶體單元的分配和使用。然而要靈活地使用struct和union 還是存在許多小技巧的,比如:元素的相關性不強時,完全是可以使用union,從而節省記憶體size; struct和union還可以相互巢狀。
三、記憶體對齊方式
union u
{
double a;
int b;
};
union u2
{
char a[13];
int b;
};
union u3
{
char a[13];
char b;
};
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
cout<<sizeof(u)<<endl; // 8
cout<<sizeof(u2)<<endl; // 16
cout<<sizeof(u3)<<endl; // 13
- 1
- 2
- 3
都知道union的大小取決於它所有的成員中,佔用空間最大的一個成員的大小。所以對於u來說,大小就是最大的double型別成員a了,所以sizeof(u)=sizeof(double)=8。但是對於u2和u3,最大的空間都是char[13]型別的陣列,為什麼u3的大小是13,而u2是16呢?關鍵在於u2中的成員int b。由於int型別成員的存在,使u2的對齊方式變成4,也就是說,u2的大小必須在4的對界上,所以佔用的空間變成了16(最接近13的對界)。
結論:複合資料型別,如union,struct,class的對齊方式為成員中對齊方式最大的成員的對齊方式。
順便提一下CPU對界問題,32的C++採用8位對界來提高執行速度,所以編譯器會盡量把資料放在它的對界上以提高記憶體命中率。對界是可以更改的,使用#pragma pack(x)巨集可以改變編譯器的對界方式,預設是8。C++固有型別的對界取編譯器對界方式與自身大小中較小的一個。例如,指定編譯器按2對界,int型別的大小是4,則int的對界為2和4中較小的2。在預設的對界方式下,因為幾乎所有的資料型別都不大於預設的對界方式8(除了long double),所以所有的固有型別的對界方式可以認為就是型別自身的大小。更改一下上面的程式:
#pragma pack(2)
union u2
{
char a[13];
int b;
};
union u3
{
char a[13];
char b;
};
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
cout<<sizeof(u2)<<endl; // 14 由於手動更改對界方式為2,所以int的對界也變成了2,u2的對界取成員中最大的對界,也是2了,所以此時sizeof(u2)=14。
cout<<sizeof(u3)<<endl; // 13 ,char的對界為1
- 1
- 2
結論:C++固有型別的對界取編譯器對界方式與自身大小中較小的一個。
struct的sizeof問題
因為對齊問題使結構體的sizeof變得比較複雜,看下面的例子:(預設對齊方式下)
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
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
同樣是兩個char型別,一個int型別,一個double型別,但是因為對界問題,導致他們的大小不同。計算結構體大小可以採用元素擺放法,我舉例子說明一下:首先,CPU判斷結構體的對界,根據上一節的結論,s1和s2的對界都取最大的元素型別,也就是double型別的對界8。然後開始擺放每個元素。
對於s1,首先把a放到8的對界,假定是0,此時下一個空閒的地址是1,但是下一個元素d是double型別,要放到8的對界上,離1最接近的地址是8了,所以d被放在了8,此時下一個空閒地址變成了16,下一個元素c的對界是4,16可以滿足,所以c放在了16,此時下一個空閒地址變成了20,下一個元素d需要對界1,也正好落在對界上,所以d放在了20,結構體在地址21處結束。由於s1的大小需要是8的倍數,所以21-23的空間被保留,s1的大小變成了24。
對於s2,首先把a放到8的對界,假定是0,此時下一個空閒地址是1,下一個元素的對界也是1,所以b擺放在1,下一個空閒地址變成了2;下一個元素c的對界是4,所以取離2最近的地址4擺放c,下一個空閒地址變成了8,下一個元素d的對界是8,所以d擺放在8,所有元素擺放完畢,結構體在15處結束,佔用總空間為16,正好是8的倍數。
特例:
#include<stdio.h>
union{
int i;
char x[2];
}a;
void main()
{
a.x[0]=10;
a.x[1]=1;
printf("%d",a.i);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
在聯合體a中定義了兩種資料型別,字元陣列x以及整形變數i.其中整形變數是16位的,陣列大小為2的字元陣列為8X2=16位。如此一來,編譯器便會為聯合體a在記憶體中開闢一個16位的空間,這個空間裡儲存聯合體的資料,但是這個空間只有16位,它既是整形變數的資料,也是字元陣列的資料。如果你的程式從字元陣列的角度解析這個空間,那麼它就是兩個字元,如果你的程式從整型的角度解析這個空間,那麼它就是一個整數。
以你的程式為例子,現在已經開闢了一個16位的空間,然後我們假定現在空間還沒有被賦值,為:
00000000 00000000
那麼在執行完程式碼
a.x[0] = 10;
a.x[1] = 1;
之後,16位的空間變為:
00000110 00000001
然後程式執行
printf(“%d”,a.i);
就是把聯合體a當成一個整數來解析,而不是字串陣列。那麼這樣一來,程式就把這16位變成了一個完整的整數:
(00000001 00000110)二進位制 = (266)十進位制
相關文章
- union 和union all 使用區別
- union all和union的區別
- sql中UNION和UNION ALL的區別SQL
- msyql jion 和 union 的區別
- oracle知識整理(1) union和union all的區別,left join和right join的區別(各種join的區別)Oracle
- swift中Class和Struct的區別SwiftStruct
- C語言:一個例子理解 union 和 structC語言Struct
- C# 中 Struct 和 Class 的區別總結C#Struct
- C++基礎(八)struct和class的區別C++Struct
- struct和typedef struct 有什麼不同呢?Struct
- union和union all 關鍵字
- require和import有啥區別?UIImport
- @AutoConfigurationPackage 和 @ComponentScan 有何區別?Package
- @Autowired和@Resource有哪些區別
- HTTP和HTTPS有哪些區別?HTTP
- 微控制器,struct ,union定義標誌,節約RAMStruct
- IPFS和區塊鏈有什麼區別區塊鏈
- sql中union和union all的用法SQL
- shim和polyfill有什麼區別
- htmlentities和htmlspecialchars 的區別有哪些HTML
- vue和react有什麼區別?VueReact
- modbus和tcp有什麼區別?TCP
- Jsp和Servlet有什麼區別?JSServlet
- SpringBoot和Spring有什麼區別?Spring Boot
- Cache 和 Buffer 有什麼區別?
- RPA和IPA有什麼區別
- int 和 Integer 有什麼區別
- rancher 和 Kubernetes有什麼區別?
- QPS和TPS有什麼區別?
- Hifi和ONT 有什麼區別
- Iterator和ListIterator有什麼區別
- DOM和BOM有什麼區別?
- xpath和dom有什麼區別?
- Activity和Fragment有什麼區別Fragment
- HTTP和HTTPS有什麼區別?HTTP
- HTTP和HTTPS的區別有哪些?HTTP
- mongodb和mysql有什麼區別MongoDBMySql
- python和nodejs有什麼區別PythonNodeJS