C语言结构体内存对齐
結構體內存對齊
如何計算結構體的大小?
首先得掌握結構體的對齊規則:
1.第一個成員在與結構體變量偏移量為0的地址處。(將第一個成員放在結構體內存的第0處)
2.其他成員變量要對齊到某個數字(對齊數)的整數倍的地址處。(從0地址處開始,偏移量逐漸增減,每個字節加一,第二個成員開始,將成員的字節大小跟對齊數(VS2019編譯器的默認對齊數是 8)進行比較,選兩者中較小的,把該變量放到小的對齊數的偏移量地址上)
對齊數 = 編譯器默認的一個對齊數與該成員大小的較小值。
- VS中默認的對齊數為8
- Linux - 沒有默認對齊數的概念
3.結構體總大小為最大對齊數(每個成員變量都有一個對齊數)的整數倍。(如果全部成員自身的的大小已經放入內存,但最后一個成員的尾字節所在的偏移量不是最大對其數的整數倍,則在最后要浪費空間直到剛好到整數倍為止)
4.如果嵌套了結構體的情況,嵌套的結構體對齊到自己的最大對齊數的整數倍處,結構體的整體大小就是所有最大對齊數(含嵌套結構體的對齊數)的整數倍。
struct S { //類型大小 VS默認對齊數 兩者中小的對齊數char c1; // 1 8 1int i; // 4 8 4double d; // 8 8 8 }; int main() {struct S s;printf("%d\n",sizeof(s)); //結構體大小為16,并不是簡單的變量大小相加 }為什么存在內存對齊?
大部分的參考資料都是這樣說的:
1.平臺原因(移植原因)︰不是所有的硬件平臺都能訪問任意地址上的任意數據的;某些硬件平臺只能在某些地址處取某些特定類型的數據,否則拋出硬件異常。
⒉.性能原因︰數據結構(尤其是棧)應該盡可能地在自然邊界上對齊。原因在于,為了訪問未對齊的內存,處理器需要作兩次內存訪問;而對齊的內存訪問僅需要一次訪問。
總體來說︰
結構體的內存對齊是拿空間來換取時間的做法。
那在設計結構體的時候,我們既要滿足對齊,又要節省空間,如何做到∶
1.讓占用空間小的成員盡量集中在一起。
2.修改默認對齊數
之前我們見過了#pragma這個預處理指令,這里我們再次使用,可以改變我們的默認對齊數。
#pragma pack(2) //設置默認對齊數為2 struct s1 {char c1;int i;char c2; }; #pragma pack() //取消設置的默認對齊數,還原為默認此時結構體大小為8,如果設置默認對齊數為1的話,則成員緊挨著存放,等于沒有對齊
offsetof宏:
用于計算結構體中某變量相對于首地址的偏移量(以字節為單位)
函數原型:offsetof (type,member)
使用:
#include <stdio.h> #include <stddef.h> //需要引入頭文件 struct s1 {char c1;int i;char c2; }; int main() {printf("%d\n", offsetof(struct s1, c1)); //0,C1在偏移量為0的地址處printf("%d\n", offsetof(struct s1, i)); //4,i在偏移量為4的地址處printf("%d\n", offsetof(struct s1, c2)); //8,C2在偏移量為8的地址處return 0; }模擬實現offsetof宏:
#include <stdio.h> struct A {char a;int b;char c;double d; }; #define OFFSETOF(struct_name,mem_name) (int)&(((struct_name *)0)->mem_name) int main() {//模擬實現宏offsetofprintf("%d\n", OFFSETOF(struct A, a));printf("%d\n", OFFSETOF(struct A, b));printf("%d\n", OFFSETOF(struct A, c));printf("%d\n", OFFSETOF(struct A, d));return 0; }解釋:定義宏時,將0強制轉換為結構體類型,只是0不再是個整型,而是個地址,是結構體的首地址,并沒有真正去創建結構體變量,然后通過->找到相應的結構體變量,&取出該變量的地址,減去0地址,再強制類型轉換為int型,就能輸出變量相對于首地址的偏移量,這里沒有減-0,因為沒有意義,如果規定首地址是0x10,那最后強轉為int之前就要減去首地址0x10,才是偏移量
總結
以上是生活随笔為你收集整理的C语言结构体内存对齐的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 寄语
- 下一篇: multisim模拟电路加法器_利用mu