聲明:文章僅為個人總結所用,鄙人菜鳥,高手勿噴,歡迎批評指正。
經常看到通過聯合體Union來判斷系統是大端還是小端,而大家的解釋通常都是:“聯合體union的存放順序是所有成員都從低地址開始存放,解答利用該特性,輕松地獲得了CPU對內存采用Little-endian還是Big-endian模式讀寫。”而我卻始終沒有找到這句話是出自哪本書。
我知道unsigned short a = 0x1122在大端中存的話就是0x1122,而如果是在小端CPU上運行的話就是0x2211。疑問:
1. 那么如果取a的低八位即a&0xff的話,是不是在大端中是0x22,而在小端中就是0x11呢?
2. 那么如果a向右移位即a>>8取得其高八位的話,是不是再大端中是0x11,而在小端中就是0x22呢?
3. 那么如果將a賦值給unsigned char b,即b = (unsigned char)a,考慮到類型強轉,取short型低八位賦值給char型,那么short型的低八位是多少呢?在大端中存的話,低八位是0x22,而在小端中存的話是0x11,那么是不是在不同架構的CPU上,結構就不相同呢?
4. 為什么通過聯合體可以判斷是大端還是小端?除了那個找不到出處的解釋外,還有其他的解釋嗎?
5. 除了網上盛傳的兩種判斷大小端的方法外,還有其他判斷大小端的方法嗎?
還是先列出網上盛傳的其中一種判斷方法吧:
void JudgeEndianByInt() { unsigned short temp = 0x1122; if(((char *)&temp)[0] == 0x11) { printf(_BIG_ENDIAN_); } else { printf(_Little_ENDIAN_); } }
我對這個函數的理解:直接根據大小端的定義來判斷,如果該數據的低地址為存放的是該數據的低數據位,那么就是小端,否則就是大端。當然我也可以理解為,將指向short型數據的指針強制轉換為char型指針,那么就要取其低地址賦值給char型指針,因此如果該低地址存放的是數據的低位,那么就是小端。
另外一種方法:
typedef union { int val_1; char val_2; }Union_Test; void JudgeEndianByUnion() { Union_Test u; u.val_1 = 0x11; if(u.val_2 == 0x11) { printf(_Little_ENDIAN_); } else { printf(_BIG_ENDIAN_); } }
我對這個函數的理解:其實這個判斷和第一個判斷原理是一樣的,都是將同一個short型的內存區的值強制轉換成char型的內存區,那么就要取其低位,如果地位存儲的是低數據位,則是小端。
然后我來分析我的那么些個疑問。
1 2 ,位操作是針對二進制位的,是針對數據的二進制位的,不關乎內存地址的東西,所以不同平台不會有影響。
3. 也不會,強轉的是數據的值,不是數據的地址,不會變化。
4. 有很多,只有能獲得地址的方法或者根據地址進行判斷的都是可行的,比如:
void JudgeEndianByMemory() { unsigned short temp = 0x11; unsigned char temp_2 = 0; memcpy(&temp_2,&temp,sizeof(temp_2)); if(temp_2 == 0x11) { printf(_Little_ENDIAN_); } else { printf(_BIG_ENDIAN_); } }
或者調用系統函數htonl ntohl等:
void HostToNet(ElemType val) { printf("val is 0x%x htonl(val) is 0x%x htonl(htonl(val)) 0x%x\n",val,htonl(val),htonl(htonl(val))); } void NetToHost(ElemType val) { printf("val is 0x%x ntohl(val) is 0x%x ntohl(ntohl(val)) 0x%x\n",val,ntohl(val),ntohl(ntohl(val))); }
因時間關系,今天暫時到此為止。
歡迎大家跟帖討論,如有紕漏,歡迎指正,謝謝~