記憶體對齊問題之大小端對齊問題 郝東東寫 所謂的大小端問題,也就是位元組序。處理器(CPU)對記憶體數據操作有兩種模式:讀和寫。這樣,處理器在讀寫一個多位元組記憶體的時候,高位元組是在記憶體的高地址還是低地址就是一個問題,不同的大小端模式可能有不同的結果。 當處理器讀寫指令針對數據不一致的時候就涉及到大小端問題, ...
記憶體對齊問題之大小端對齊問題
郝東東寫
所謂的大小端問題,也就是位元組序。處理器(CPU)對記憶體數據操作有兩種模式:讀和寫。這樣,處理器在讀寫一個多位元組記憶體的時候,高位元組是在記憶體的高地址還是低地址就是一個問題,不同的大小端模式可能有不同的結果。
當處理器讀寫指令針對數據不一致的時候就涉及到大小端問題,例如:將0x7654321放入記憶體里,然後在記憶體首地址用單位元組讀取命令,這就涉及到處理器是大端還是小端。對於小端處理器,寫記憶體的時候會將記憶體的低地址處放入數據源的低位元組,在記憶體的高地址處放入數據源的高位元組;大端模式則剛好相反。這個可以參照下麵這個例子:
1 Char c1,c2,c3,c4; 2 3 Unsigned char *p; 4 5 Unsigned long a=0x76543210; 6 7 P=(unsigned char *)&a; 8 9 C1=*p; 10 11 C2=*(p+1); 12 13 C3=*(p+2); 14 15 C4=*(P+3);
這樣的話,可以輸出這四個值,在小端處理器運行的時候:c1=0x10;c2=0x32;c3=0x54;c4=0x76;這是由於在儲存a的時候,需要4個連續的位元組,小端模式最低的位元組將被放置在記憶體的最低位。0x10被放置在第一個位元組。同理大端模式則相反。C4=0x10;
下麵介紹幾種方法,可以直接判斷我們的電腦是什麼模式儲存數據:第一種方案:利用聯合體。程式如下:
1 #include<stdio.h> 2 3 #include<stdlib.h> 4 5 int cpu_return() 6 7 { 8 9 union perk 10 11 { 12 13 int a; 14 15 char b; 16 17 }c; 18 19 c.a==1; 20 21 return(c.b==1); 22 23 } 24 25 26 27 int main() 28 29 { 30 31 printf("%d\n",cpu_return()); 32 33 }
返回0則是小端模式,1是大端模式。
第二種方案:構造共用體,用長整型來訪問,依次輸出每個位元組,程式如下:
1 #include<stdio.h> 2 3 #include<stdlib.h> 4 5 typedef struct byte_4 6 7 { 8 9 unsigned char byte0; 10 11 unsigned char byte1; 12 13 unsigned char byte2; 14 15 unsigned char byte3; 16 17 }byte4; 18 19 typedef union data32 20 21 { 22 23 unsigned long data; 24 25 byte4 databyte; 26 27 }data_32; 28 29 int main(void) 30 31 { 32 33 data_32 a; 34 35 a.data=0x11223344; 36 37 printf("databyte(0,1,2,3):(%x,%x,%x,%x)\n",a.databyte.byte0,a.databyte.byte1,a.databyte.byte2,a.databyte.byte3); 38 39 return 0; 40 41 }
小端輸出為:databyte(0,1,2,3):(44,33,22,11)
大端輸出為:databyte(0,1,2,3):(11,22,33,44)
第三種方案:直接看最低位儲存的值來判斷:
1 #include<stdio.h> 2 3 #include<stdlib.h> 4 5 int testcpu() 6 7 { 8 9 unsigned int x=1; 10 11 if(1==*(unsigned char *)&x) 12 13 printf("Little Endian\n"); 14 15 else 16 17 printf("Big Endian\n"); 18 19 return(1==*(unsigned char *)&x); 20 21 } 22 23 int main() 24 25 { 26 27 printf("CPU:%d\n",testcpu()); 28 29 return 0; 30 31 }
小端返回1,大端返回0;
最後,linux中網路編程中要特別註意大小端問題,因為網路位元組序和本機位元組序通常是需要轉換的,比如判斷一個udp報文是否為dhcp報文,需要將報文中的udp埠進行位元組序轉換,通常調用ntohs去轉換後才可以判斷和賦值。