引言C語言的精粹是程式要可以隨意操縱自己程式空間的任意記憶體,從這方面來說,C語言編程算是面向機器的編程。那麼,熟悉C的資料如何儲存就是顯得很重要了。本篇內容就是記錄自己探索C語言的資料結構在記憶體如何儲存的過程。結論只在下麵條件下得到驗證:作業系統位元:32編譯器:gcc version 4.6.3(ubuntu)mingw32-gcc資料存放區方式:小端儲存大端儲存和小端儲存大端儲存和小端儲存指的是指記憶體位址的低位存的是資料的高位還是低位。舉個例子:int i=0x12345678大端系統儲存:小端系統儲存:當資料從不同的系統流到不同的系統需要轉換(位元組序轉換),最典型的是網路的大端位元組序轉換為x86的小端位元組序位元組對齊C語言的資料結構一般來說是不同資料類型的彙總物,裡麵包含了不同的資料類型,因為資料結構不會像C++的類那樣給我們提供那麼多的功能,所以它的儲存就非常簡單。僅僅是將資料直接按照順序進行儲存。比如下面這個資料結構:
struct str4_t{unsigned char c1[1];unsigned char c2[2];unsigned char c3[3];unsigned char c4[5];}str4;
它在記憶體中的就是按照順序儲存
sizeof(str4)的大小是11,1+2+3+5=11剛好。怎麼樣?很簡單吧!不急呵,看看下面一個資料結構:
struct str3_t{unsigned char ac[3];unsigned short s;}str3;
應該是3+2=5吧。但是事實上呢sizeof(str3)是等於6的。為何呢?我們看看記憶體它是怎麼存的:
上面黃色是ac,淺藍色的是s。白色是沒有存資料的。它被空出來了,這就是傳說中的
位元組對齊了。開頭說了,我的作業系統是32位的,作業系統在我們的程式空間一次讀出來的資料是32位(我們的程式記憶體是作業系統虛擬出來的),32位就是4個位元組,如果上面把白色的去掉,我們訪問s的時候就需要2次才能取到s的值,這樣就很浪費時間啦。所以要位元組序對齊。再看看下面一個資料結構:
struct str2_t{unsigned short s;unsigned int i;unsigned char c;}str2;
這個應該是多少呢?按照位元組序對齊的原則應該是4+4+1=9.但是非常遺憾,結果是12.難道是因為str2這個資料結構要位元組序對齊?這樣也不對啊,上面的str3是6啊,也不是4的倍數啊。原因何在,百度、google之後發現還有一個規則:結構體的整體大小必須是結構佔用最大位元組的成員的整數倍。str2最大是int型,就是4個位元組,所以啊,只能是12了。附:測試代碼
#include <stdio.h>#include <string.h>#define BUFFERSIZE 120unsigned char *p;struct str1_t{unsigned char c;unsigned short s;unsigned int i;unsigned long l;}str1;struct str2_t{unsigned short s;unsigned int i;unsigned char c;}str2;struct str3_t{unsigned char ac[3];unsigned short s;}str3;struct str4_t{unsigned char c1[1];unsigned char c2[2];unsigned char c3[3];unsigned char c4[5];}str4;int main(){int in,i,len;in = 0x12345678;p = (unsigned char *)∈len = sizeof(in);printf("int size:%d\r\n", len);for(i=0; i<len; i++)printf("%2X ", *(p+i));printf("\r\n\r\n");str1.c = 0x12;str1.s = 0x34;str1.i = 0x56;str1.l = 0x78;p = (unsigned char *)&str1;len = sizeof(str1);printf("str1 size:%d\r\n", len);for(i=0; i<len; i++)printf("%2X ", *(p+i));printf("\r\n\r\n");str2.s = 0x12;str2.i = 0x34;str2.c = 0x56;p = (unsigned char *)&str2;len = sizeof(str2);printf("str2 size:%d\r\n", len);for(i=0; i<len; i++)printf("%2X ", *(p+i));printf("\r\n\r\n");str3.ac[0] = 0x12;str3.ac[1] = 0x34;str3.ac[2] = 0x56;str3.s = 0x78;p = (unsigned char *)&str3;len = sizeof(str3);printf("str3 size:%d\r\n", len);for(i=0; i<len; i++)printf("%2X ", *(p+i));printf("\r\n\r\n");str4.c1[0] = 0x1;str4.c2[0] = 0x2;str4.c2[1] = 0x3;str4.c3[0] = 0x4;str4.c3[1] = 0x5;str4.c3[2] = 0x6;str4.c4[0] = 0x7;str4.c4[1] = 0x8;str4.c4[2] = 0x9;str4.c4[3] = 0xa;str4.c4[4] = 0xb;p = (unsigned char *)&str4;len = sizeof(str4);printf("str4 size:%d\r\n", len);for(i=0; i<len; i++)printf("%2X ", *(p+i));printf("\r\n\r\n");unsigned short s = 0xF1;unsigned int i2 = 0xF2;unsigned char c = 0xF3;unsigned char buffer2[20];//avoid the memery overflowmemset(buffer2, 0 , sizeof(buffer2));struct str2_t *pstr2;pstr2 = (struct str2_t *)&s;printf("%X %X %X\r\n", pstr2->s, pstr2->i, pstr2->c);return 0;}