c语言对齐方式研究笔记
c語言對齊方式研究筆記
為什么要對齊
TragicJun 發表于 2006-9-18 9:41:00 現代計算機中內存空間都是按照byte劃分的,從理論上講似乎對任何類型的變量的訪問可以從任何地址開始,但實際情況是在訪問特定類型變量的時候經常在特定的內存地址訪問,這就需要各種類型數據按照一定的規則在空間上排列,而不是順序的一個接一個的排放,這就是對齊。
對齊的作用和原因:各個硬件平臺對存儲空間的處理上有很大的不同。一些平臺對某些特定類型的數據只能從某些特定地址開始存取。比如有些架構的CPU在訪問一個沒有進行對齊的變量的時候會發生錯誤,那么在這種架構下編程必須保證字節對齊.其他平臺可能沒有這種情況,但是最常見的是如果不按照適合其平臺要求對數據存放進行對齊,會在存取效率上帶來損失。所謂內存對齊,是為了讓內存存取更有效率而采用的一種編譯階段優化內存存取的手段。
比如對于int x;(這里假設sizeof(int)==4),因為cpu對內存的讀取操作是對齊的,如果x的地址不是4的倍數,那么讀取這個x,需要讀取兩次共8個字節,然后還要將其拼接成一個int,這比存取對齊過的x要麻煩很多。(比如操作系統一次允許讀4個字節,從內存4-7存放的是一個int,此時如果從地址4開始讀,恰好可以讀出一個int,但是如果從地址3開始讀,需要讀兩次,然后進行拼接,形成一個int)。
怎么對齊
結構體對齊可以分為兩種情況,結構體對齊和結構體內成員對齊
- 結構體對齊
結構體對齊使用 **__attribute__((aligned(n)))**偽指令來設置結構體n字節對齊,在嵌入式中FATFS一般會要求緩沖區512字節對齊。
有以下結構體
typedef struct{char a;int b;} pack4_t __attribute__((aligned(512)));使用 __attribute__((aligned(512)))偽指令來設置結構體512字節對齊,則a的地址一定是512的倍數。
- 結構體內成員對齊
結構體內成員對齊使用 , 一般聯合體或者結構體強制轉化時,需要注意結構體成員對齊信息
#pragma pack(n) //n字節對齊
/* 用戶代碼 */
…
#pragma pack() //恢復默認對齊
偽指令來設置結構體內成員n字節對齊
有以下結構體
typedef struct{char a;int b;} pack4_t;在MDK默認情況下,分配內存時,a時char類型,占一個字節,所以對對齊沒有要求在a分配內存后,會接著a的內存地址對b進行內存分配。
由于b是int類型,占4個字節,所以默認會4字節對齊,也就是b的地址應該是4的倍數,如果a挨著的地址不是4的倍數,則會向后順延,直至地址為4的倍數,然后將對應的地址空間分配給b,a和b中間的地址空間則為空的,其他的類似。
使用1字節對齊時,a時char類型,占一個字節,所以對對齊沒有要求在a分配內存后,會接著a的內存地址對b進行內存分配。
由于b是int類型,占4個字節,默認會4字節對齊,但是用戶指定了使用1字節對齊,所以b也使用1字節對齊,也就是b的地址應該緊挨著a,其他的類似。
使用1字節對齊時,a時char類型,占一個字節,所以對對齊沒有要求在a分配內存后,會接著a的內存地址對b進行內存分配。
由于b是int類型,占4個字節,默認會4字節對齊,但是用戶指定了使用2字節對齊,所以b使用2字節對齊,也就是b的地址應該是2的倍數,如果a挨著的地址不是2的倍數,則會向后順延,直至地址為2的倍數,然后將對應的地址空間分配給b,a和b中間的地址空間則為空的,其他的類似。
使用1字節對齊時,a時char類型,占一個字節,所以對對齊沒有要求在a分配內存后,會接著a的內存地址對b進行內存分配。
由于b是int類型,占4個字節,所以默認會4字節對齊,也就是b的地址應該是4的倍數,如果a挨著的地址不是4的倍數,則會向后順延,直至地址為4的倍數,然后將對應的地址空間分配給b,a和b中間的地址空間則為空的,這里看起來和MDK默認的分配一樣,但是當b為double類型,占8個字節時,當使用默認分配時,b的地址需要是8的數倍,而這里只需要是4的倍數。
為了更加清楚理解,這里讓結構體更復雜點
typedef struct{char a;int b;char c;uint16_t d;int e;char f;double g;} pack4_t;在STM32上實測
#pragma pack(4) typedef struct{char a;int b;char c;uint16_t d;int e;char f;double g;} pack4_t __attribute__((aligned(512))); #pragma pack()#pragma pack(2) typedef struct{char a;int b;char c;uint16_t d;int e;char f;double g;} pack2_t __attribute__((aligned(512))); #pragma pack()#pragma pack(1) typedef struct{char a;int b;char c;uint16_t d;int e;char f;double g;} pack1_t __attribute__((aligned(512))); #pragma pack()typedef struct{char a;int b;char c;uint16_t d;int e;char f;double g;} pack_t __attribute__((aligned(512)));pack4_t pack4 ; pack2_t pack2 ; pack1_t pack1 ; pack_t pack ;int main(void) { printf("\r\n1字節對齊 %x %x %x %x %x %x %x\r\n",&pack1.a, &pack1.b, &pack1.c, &pack1.d, &pack1.e , &pack1.f, &pack1.g);printf("\r\n2字節對齊 %x %x %x %x %x %x %x\r\n",&pack2.a, &pack2.b, &pack2.c, &pack2.d, &pack2.e , &pack2.f, &pack2.g);printf("\r\n4字節對齊 %x %x %x %x %x %x %x\r\n",&pack4.a, &pack4.b, &pack4.c, &pack4.d, &pack4.e , &pack4.f, &pack4.g);printf("\r\nMDK默認對齊 %x %x %x %x %x %x %x\r\n",&pack.a, &pack.b, &pack.c, &pack.d, &pack.e , &pack.f , &pack.g);while(1){} }打印結果
1字節對齊 20005600 20005601 20005605 20005606 20005608 2000560c 2000560d2字節對齊 20005800 20005802 20005806 20005808 2000580a 2000580e 200058104字節對齊 20005a00 20005a04 20005a08 20005a0a 20005a0c 20005a10 20005a14MDK默認對齊 20005400 20005404 20005408 2000540a 2000540c 20005410 20005418總結
以上是生活随笔為你收集整理的c语言对齐方式研究笔记的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: freeRtos学习笔(2)任务管理
- 下一篇: freeRtos学习笔(3)临界区管理