struct 成員的對齊方式

2021-07-25 07:45:46 字數 4114 閱讀 3252

//用乙個巨集定義find求結構體struct s中某個成員變數member相對struct s的偏移量.

//思考:若struct s的位址為0,則其成員member的位址就是其相對於s的偏移量

//擴充套件: <1>sizeof(struct s) 不一定等於 sizeof(struct s中的每乙個成員)的和

//      <2>結構體大小不僅由成員的大小決定(sizeof(member)),而且還要考慮編譯器用來優化的對齊。

// 編譯器的優化對齊(alignment), 是為了減少訪問匯流排的次數。

//由於資料匯流排的位數(由機器字長決定),為了減少資料訪問的次數。

//這樣可以保證機器字長整數倍的基本型別(而非自定義型別)

//能夠通過 sizeof(基本型別)/sizeof(size_t)次匯流排訪問完成;

//通過實驗, 我得出的對齊規則是:

// char  偏移位址二進位制的最後一位:0/1;即1的倍數的位址對齊性;即任意對齊性;

// short 偏移位址二進位制的最後一位:0;  即2的倍數字址的對齊性;即偶數字址對齊性;

// int     偏移位址二進位制的最後兩位:00; 即4的倍數的位址對齊性;

// float  偏移位址二進位制的最後兩位:00; 即4的倍數的位址對齊性;

// long  偏移位址二進位制的最後兩位:00; 即4的倍數的位址對齊性;

// long long   偏移位址二進位制的最後三位:000;即8的倍數的位址對齊性;

// double偏移位址二進位制的最後三位:000;即8的倍數的位址對齊性;

//總之,struct中基本型別成員的偏移位址時一定是sizeof(基本型別)的整數倍,

//自定義型別偏移位址的對齊性是任意的.

//推過這種方式,就能解釋sizeof(struct s)不等於所有成員的sizeof的和。

// sizeof(struct s) 除了滿足以上偏移位址對齊外,

// 是其大小為其基本型別成員的sizeof值最大的成員的sizeof值的整數倍

// 也就是說為最大的基本型別的sizeof值得整數倍。

程式舉例:

[cpp]view plain

copy

#include 

using

namespace

std;  

struct

cc ;  

struct

student ;  

//用乙個巨集定義find求結構體struct s中某個成員變數member相對struct s的偏移量.

//思考:若struct s的位址為0,則其成員member的位址就是其相對於s的偏移量

//擴充套件: <1>sizeof(struct s) 不一定等於 sizeof(struct s中的每乙個成員)的和

//      <2>結構體大小不僅由成員的大小決定(sizeof(member)),而且還要考慮編譯器用來優化的對齊。

// 編譯器的優化對齊(alignment), 是為了減少訪問匯流排的次數。

//由於資料匯流排的位數(由機器字長決定),為了減少資料訪問的次數。

//這樣可以保證機器字長整數倍的基本型別(而非自定義型別)

//能夠通過 sizeof(基本型別)/sizeof(size_t)此匯流排訪問完成;

//通過實驗, 我得出的對齊規則是:

// char  偏移位址二進位制的最後一位:0/1;即1的倍數的位址對齊性;即任意對齊性;

// short 偏移位址二進位制的最後一位:0;  即2的倍數字址的對齊性;即偶數字址對齊性;

// int   偏移位址二進位制的最後兩位:00; 即4的倍數的位址對齊性;

// float 偏移位址二進位制的最後兩位:00; 即4的倍數的位址對齊性;

// long  偏移位址二進位制的最後三位:000;即8的倍數的位址對齊性;

// double偏移位址二進位制的最後三位:000;即8的倍數的位址對齊性;

//總之,struct中基本型別成員的偏移位址時一定是sizeof(基本型別)的整數倍,

//自定義型別偏移位址的對齊性是任意的.

//推過這種方式,就能解釋sizeof(struct s)不等於所有成員的sizeof的和。

// sizeof(struct s) 除了滿足以上偏移位址對齊外,

// 是其大小為其基本型別成員的sizeof值最大的成員的sizeof值的整數倍

// 也就是說為最大的基本型別的sizeof值得整數倍。

#define find(s, member)  (size_t)(&((*((s *)((void *)0))).member))

#define find1(s, member) (size_t)(&(*((s *)0)).member)

#define find2(s, member) (size_t)(&(((s *)0)->member))

#define displacement1(structure, member) (size_t) &((*((structure *)0)).member)

#define displacement2(structure, member) (size_t) &(((structure *)0)->member)

struct

c ;  

struct

ccc ;  

struct

d ;  

struct

e ;           //24

struct

f ;  

struct

g ;  

// 12

intmain()    

補充:首先要明確sizeof不是函式,也不是一元運算子,//這個有待商榷,因為運算子優先順序裡有它。

他是個類似巨集定義的特殊關鍵字,sizeof();

括號內在編譯過程中是不被編譯的,而是被替代型別,

如 int a=8;sizeof(a);

在編譯過程中,它不管a的值是什麼,只是被替換成型別 sizeof(int); 結果為4.

如果sizeof(a=6);呢,也是一樣的轉換成a的型別,但是要注意 因為a=6是不被編譯的,所以執行完sizeof(a=6);a的值還是8,是不變的!

記住以下幾個結論:

1.unsigned影響的只是最高位bit的意義(正負),資料長度不會被改變的。所以sizeof(unsigned int) == sizeof(int);

2.自定義型別的sizeof取值等同於它的型別原形。如typedef short word;sizeof(short) == sizeof(word)。

3.對函式使用sizeof,在編譯階段會被函式返回值的型別取代。如:int f1();

cout <

char a = 「abcdef 「;

int b[20] = ;

char c[2][3] = ;

cout << sizeof(a) << endl; // 7

cout << sizeof(b) << endl; // 20*4

cout << sizeof(c) << endl; // 6

陣列a的大小在定義時未指定,編譯時給它分配的空間是按照初始化的值確定的,也就是7,包括『\0』的。

6.字串的sizeof和strlen,用例子說明:

char a = 「abcdef 「;

char b[20] = 「abcdef 「;

string s = 「abcdef 「;

cout << strlen(a) << endl; // 6,字串長度

cout << sizeof(a) << endl; // 7,字串容量

cout << strlen(b) << endl; // 6,字串長度

cout << sizeof(b) << endl; // 20,字串容量

cout << sizeof(s) << endl; //4, 這裡不代表字串的長度,而是string類的大小

cout << strlen(s) << endl; // 錯誤!s不是乙個字元指標。

cout << strlen(s.c_str()) << endl;

a[1] = '\0';

cout <

參考 :

struct的成員對齊

struct 的成員對齊 intel 微軟等公司曾經出過一道類似的面試題 include pragma pack 8 struct example1 struct example2 pragma pack int main int argc,char argv 問程式的輸入結果是什麼?答案是 8 1...

struct的成員對齊

1struct 的成員對齊 intel 微軟等公司曾經出過一道類似的面試題 include pragma pack 8 struct example1 struct example2 pragma pack int main int argc,char argv 問程式的輸入結果是什麼?答案是 8 ...

struct的成員對齊

intel 微軟等公司曾經出過一道類似的面試題 1.include 2.pragma pack 8 3.struct example1 4.8.struct example2 9.14.pragma pack 15.int main int argc,char argv 16.問程式的輸入結果是什麼...