系統的大小端

2021-08-14 14:56:17 字數 3336 閱讀 7892

比如有個十六進製制數0x12345678(為什麼用十六進製制數舉例?其實計算機只認識0和1,不管是字元還是數字,放到記憶體中後都是轉換成乙個二進位制數進行儲存,也就是一堆0和1。具體如何轉換成二進位制,和如何儲存的,就涉及到另乙個知識點了,這裡不做過多解釋),當然也可以用十進位制數,如305419896**換成十六進製制後還是0x12345678…),二進位制?當然行,再轉換成十六進製制嘛!不轉換行不行?!額…應該行吧,不過我覺得會比較麻煩。我的理解就是:學過c語言的應該都知道,我們申請記憶體空間的時候都是我要malloc多少個位元組(1位元組等於8位),而不是我要malloc多少個位(比如我要malloc乙個位元組的空間,而不是我要malloc八位的空間);還有,描述變數型別的大小的時候都是:(32位系統下)char佔1個位元組、int佔4個位元組等等,而不是char佔8位、int佔32位。為什麼用位元組而不是位來描述呢?再講下我的理解:據我所見,用來描述位址值的都是用十六進製制,如0x00、0x01這兩個位址(它們分別佔1個位元組,十六進製制中,每兩個符號位佔一位元組);如果用二進位制應該也可以,那就可能這樣,00000000、000000001(這兩個位址也分別佔乙個位元組),顯然,用二進位制進行描述就顯得冗長,還是十六進製制描述簡單些。以上都是個人理解,是否完全正確,我也不確定,保留意見。綜上兩個解釋,因此這裡就用十六進製制數來舉例了。

廢話了一大堆,回歸正題(這裡也說明,要掌握乙個知識點,肯定還會牽扯到更多其它知識點,並不是單單學乙個就夠了的)。這裡再解釋下,0x12345678這個數在記憶體中並不是佔乙個位元組的,它在一段連續的記憶體中分別儲存,可能0x12存在乙個位元組的記憶體位址中、0x34存在接下來的記憶體位址中,以此類推。那0x12345678這個數的高低位元組怎麼判斷呢?學過數學的都知道從右到左的讀個、十、百…這裡的個位就是低位,十位相對於個位就是高位了。十六進製制的高低位元組也是如此0x78是低位元組,0x12是高位元組(低到高是從右到左)。這樣描述就很清楚了吧,忘記了就念個十百吧。

為什麼要弄清上面講的兩個概念呢?那是因為:

資料的低位元組存放到記憶體的低位址中,高位元組存到高位址中。並且小端模式下優先將資料填充到記憶體的低位址中。

大與小正好相反。資料的低位元組存放到記憶體的高位址中,高位元組存到低位址中,且資料優先填充到高位址上。

這就是大小端儲存資料的差異了。再說個簡單的記憶方式:如果資料的實際情況與存在記憶體中的方式不一樣,就是小端模式,一樣的就是大端模式了(當然,不管是大端模式還是小端模式,同乙個資料的值是不會變的)。大端模式適合人類理解,小端模式低對低,高對高,可能就適合計算機理解了。

概念理解了,接下來怎麼驗證自己的系統是大端還是小端呢?當然是用**了。上**(解釋都在**中):

/*

* @endian_test.c

* @author:wangtal

*/#include

int main(int argc, char* argv)

utest = },

utest1 = ;

printf("utest.n:0x%x\n", utest.n);

printf("utest.s[0]:0x%x\n", utest1.s[0]);

// 不用聯合體也可以。直接定義乙個int型變數,然後定義乙個char型

// 變數儲存到int型變數第乙個位元組的內容,由於char型變數佔乙個位元組

// 所以後面剩餘位元組的資料會丟失掉。最後當然是列印出來了,如碼所示

int n = 0x12345678;

// 然後再通過*來取位址中的內容

char s = *((char*)&n);

printf("s:0x%x\n", s);

// 再多說乙個,其實用上面那兩個就夠了的

// c語言中,指標型別是可以強制轉換的,當然有一定的前提條件

// 如果兩個位址大小相等,也就是等量個位元組數,就可以相互轉換

// 成另一種型別的指標.

// s[4]是佔4個位元組,但是如果將n的位址強制轉換並賦值給s是會

// 報錯的(大小不匹配).如果像上面那樣,將n的第乙個位元組擷取儲存

// 到s[0]中...但這不是我想要的結果,我要乙個變數指向n的整個位址

// 這就需要用到強大的結構體了,像下面這樣,用struct封裝s[4],並

// 定義該型別的乙個變數stest,然後賦值,如碼所示

struct stest = ;

// 下面這句的意思就是取stest的位址,轉換為int*型別

// 再通過*取出其中的內容賦值給n

n = *(int*)&stest;

printf("n:0x%x\n", n);

// 再寫幾行**解釋下不同模式下資料優先填充到哪

// 將n賦值為0x12,它佔1個位元組,而int佔4個

// 然後將n的位址中的內容賦值給stest,並列印每個位元組中的內容

n = 0x12;

// 這句可能看起來有些奇葩,其實知道原理的話也沒什麼奇葩

// 先解釋下意思,取n的位址,轉換成stest這個變數型別的指標

// 再通過*取出其中的內容賦值給stest

// 簡單解釋下,因為stest沒有具體的名稱,所以通過typeof(具體用法自己搜尋)

// 獲取它的型別,加個*就表示這種型別的指標(如int*)

stest = *(typeof(stest)*)&n;

// 最後將stest中4個位元組中的內容都列印出來

printf("stest.s[0]:0x%x\n", stest.s[0]);

printf("stest.s[1]:0x%x\n", stest.s[1]);

printf("stest.s[2]:0x%x\n", stest.s[2]);

printf("stest.s[3]:0x%x\n", stest.s[3]);

return

0;}

以上**的執行結果:

解釋下結果(我的電腦是小端模式):

第一行,我們給utest.s的四個位元組賦值了四個數(它們在記憶體中依次從低位址到高位址儲存,0x12在低位址),然後通過utest.n讀取並列印,但是列印的時候需要轉換成實際資料的,由於我的電腦是小端,低位址中的內容就放到低位元組中所以列印結果就是0x78563412。

第二行,結果之所以是0x78,是因為只擷取了第乙個位元組的內容。

第三行,原理同第二行。

第四行,0x12在低位址,小端模式,轉換後放在低位元組,所以結果是0x78563412。

剩下幾行說明了小端模式下,資料優先填充到低位址中,stest.s[0]的位址是低位址,它的內容是0x12,其餘位址沒有資料填充,所以都為0。

到此結束。我覺得該記錄的點都記在裡面了,如果有人看後還有疑問或發現存在問題,歡迎提出。:)

系統大小端檢測

大小端的引入 在計算機系統中,我們是以位元組為單位的,每個位址單元都對應著乙個位元組,乙個位元組為8bit。但是在c語言中除了8bit的char之外,還有16bit的short型別,32bit的int型別,另外位數大於8位的處理器,例如16位或者32位bit的處理器,由於暫存器寬度大於乙個位元組,要...

判斷系統大小端模式

端模式 endian 的這個詞出自jonathan swift書寫的 格列佛遊記 這本書根據將雞蛋敲開的方法不同將所有的人分為兩類,從圓頭開始將雞蛋敲開的人被歸為big endian,從尖頭開始將雞蛋敲開的人被歸為littile endian。小人國的內戰就源於吃雞蛋時是究竟從大頭 big endi...

Linux系統大小端判斷

大小端定義 小端 little endian 低位位元組存放在記憶體的低端位址,高位位元組存放在記憶體的高階位址 大端 big endian 高位位元組存放在記憶體的低端位址,低位位元組存放在記憶體的高階位址。源 原始碼檔案 endian.c 編 譯 gcc o endian endian.c 執 ...