學習筆記-CC++-結構體與sizeof記憶體對齊-必考題及答案
- 2020 年 2 月 18 日
- 筆記
記憶體對齊
#pragma pack (n)這個語句用於設置結構體的記憶體對齊方式,具體作用下面再說。在linux gcc下n可取的值為:1,2,4,當n大於4時按4處理。如果程式中沒用顯試寫出這個語句,那麼在linux gcc下,它會對所有結構體都採用#pragma pack (4)的記憶體對齊方式。需要注意的是,在不同的編譯平台上默認的記憶體對齊方式是不同的。如在VC中,默認是以#pragma pack (8)的方式進行對齊。
記憶體對齊總規則:
結構體成員的地址必須安排在成員大小的整數倍上或者是#pragma pack(n)所指定的n的倍數上;取兩者的最小值,即MIN(sizeof(mem), n),稱MIN(sizeof(mem), n)為該結構體的成員對齊模數。同時該結構體的總大小必須為MIN(n, MAX(sizeof(mem1), siezof(mem2)…))的整數倍;而稱MIN(n, MAX(sizeof(mem1), siezof(mem2)…))為該結構體的對齊模數。
記憶體對齊細則:
下面的3條細則符合上面所說的總規則;這裡的偏移指某一個數據成員的首地址到該結構體頭的地址偏移。
(1)對結構體的成員,第一個數據位於偏移為0的位置,以後每個數據成員的偏移量必須是成員對齊模數的倍數。
(2)為結構體的一個成員開闢空間之前,編譯器首先檢查預開闢空間的偏移是否為成員對齊模數的整數倍,若是,則存放本成員,反之,則在本成員與上一成員之前填充一定的位元組,從而達到整數倍的要求。
(3)在數據成員完成自身的對齊後,結構體本身也要進行對齊。意思是該結構體的大小必須是結構體的對齊模數的整數倍。如果其大小不是,那麼則在最後一個成員的後面填充位元組。
記憶體對齊完整版規則
1:數據成員對齊規則:結構(struct)(或聯合(union))的數據成員,第一個數據成員放在offset為0的地方,以後每個數據成員存儲的起始位置要從該成員大小或者成員的子成員大小(只要該成員有子成員,比如說是數組,結構體等)的整數倍開始(比如int在32位機為4位元組,則要從4的整數倍地址開始存儲。
如果 n < sizeof(mem), 是從n的整數倍開始。
2:結構體作為成員:如果一個結構里有某些結構體成員,則結構體成員要從其內部最大元素大小的整數倍地址開始存儲.(struct a里存有struct b,b里有char,int ,double等元素,那b應該從8的整數倍開始存儲.)
注char【8】看做 8個元素,而不是一個元素
(3)在數據成員完成自身的對齊後,結構體本身也要進行對齊。意思是該結構體的大小必須是結構體的對齊模數的整數倍。如果其大小不是,那麼則在最後一個成員的後面填充位元組。
Type |
存儲所佔位元組 |
對齊方式(變數存放的起始地址相對於結構的起始地址的偏移量) |
Alignment 和左邊一列一個意思 |
---|---|---|---|
char |
1 |
偏移量必須為sizeof(char)即1的倍數 |
在位元組邊界上對齊 |
short (16-bit) |
2 |
偏移量必須為sizeof(short)即2的倍數 |
在雙位元組邊界上對齊 |
int and long (32-bit) 指針(unsigned long int) |
4 在32位系統下int 和long是一樣的? |
偏移量必須為sizeof(int)即4的倍數 |
在4位元組邊界上對齊 |
枚舉類型的默認類型是int型 |
4 |
|
|
float |
4 |
偏移量必須為sizeof(float)即4的倍數 |
在4位元組邊界上對齊 |
double long long |
8 |
偏移量必須為sizeof(double)即8的倍數 |
在8位元組邊界上對齊 |
structure |
|
|
單獨考慮結構體的個成員,它們在不同的位元組邊界上對齊。 其中最大的位元組邊界數就是該結構的位元組邊界數。 |
靜態變數 |
0 |
|
MSDN原話:Largest alignment requirement of any member |
空結構體 |
1 必須保證結構體的每一個實例在記憶體中都有獨一無二的地址 |
|
|
***************************************>【例題】<*****************************************
例題1:
typedef struct{
int i;
char c;
short s;
char buf[21];
}s; //32
例題2:
typedef struct {
int id; //[0]..[3]
char name[50]; // [4]..[53]
int age; //[56..59]
char gender[10]; //[60..71]
} s; // 72
例題3:
struct stu{
char sex; //[0]
int length; // [4]…[7]
char name[10]; //[8]..[17] //按照模 sizeof(int) = 4補齊
};
sizeof (struct stu) = 20
例題5:
enum DataType {
IntData, CharData, VcharData
}; //4
struct s {
char ItemNAme[30]; //[0..29]
enum DataType ItemType; //[32..35]
char ItemDecr[50]; //[36..85]
int ItemLength; //[88..91]
}; //92
printf("%dn", sizeof(struct s));
例題7:
typedef struct
{
char str;
short x;
int num;
double xx;
}s1;
typedef struct
{
char str;
int num;
short x;
double xx;
}s2;
例題8:
微軟&Intel筆試題:
#pragma pack(8)
struct s1
{
short a;
long b; //4
}; //8
struct s2
{
char c; //[0]
s1 d; //[4..11]
long long e; // [16..23]
}; //24
#pragma pack()
問:
1.sizeof(s2) = ?
2.s2的c後面空了幾個位元組接著是d?
答:
- 24
- 3個
例題9:
華為筆試題:
typedef struct {
unsigned char ucld :1;
unsigned char ucpara0 :2;
unsigned char ucstate :6;
unsigned char uctail :4;
unsigned char ucavail;
unsigned char uctail2 :4;
unsigned long uldate;
} s;
//s在位元組對齊分別為1,4的情況下佔用空間大小是多少?還有那個冒號是什麼意思