大小端字節(jié)序

字節(jié)序和大小端

對(duì)于位數(shù)大于8位的處理器鸣奔,例如16位或者32位的處理器静稻,由于寄存器寬度大于一個(gè)字節(jié)域仇,那么必然存在著一個(gè)如何將多個(gè)字節(jié)安排的問(wèn)題放椰。

小端模式:(高高低低)高字節(jié)放在高地址作烟,低字節(jié)放在低地址
大端模式:(高低低高)高字節(jié)放在低地址,低字節(jié)放在高地址

舉個(gè)例子庄敛,數(shù)值 0x12345678俗壹,其中 0x12 這一端是高位字節(jié)科汗,0x78 這一端是低位字節(jié)藻烤。
該數(shù)值的存儲(chǔ)順序是這樣的:

image.png
image 2.png

為什么沒(méi)有統(tǒng)一?

檢查奇偶性 (小端占優(yōu))

小端序優(yōu)勢(shì)最明顯 的头滔,大概就是檢查奇偶性怖亭,即通過(guò)查看個(gè)位數(shù),確定某個(gè)數(shù)字是奇數(shù)還是偶數(shù)坤检。


bg2022060112.jpeg

以123456為例兴猩,大端序從左到右排列,計(jì)算機(jī)必須一直讀到最后一位的個(gè)位數(shù)6早歇,才能確定這是偶數(shù)倾芝。
小端序是從右到左排列,個(gè)位數(shù)在第一位箭跳。所以晨另,只要讀取第一位,就能確定它是偶數(shù)谱姓。

檢查正負(fù)號(hào) (大端占優(yōu))

一個(gè)類似的場(chǎng)景是檢查正負(fù)號(hào)借尿,確定一個(gè)數(shù)是正數(shù)還是負(fù)數(shù)。


bg2022060113.jpg

大端序的符號(hào)位在左邊第一位屉来,小端序的符號(hào)位在右邊最后一位路翻。所以,大端序有優(yōu)勢(shì)茄靠,只看第一位就能知道是不是負(fù)數(shù)茂契。

比較大小 (小端占優(yōu))

下一個(gè)操作是比較大小。現(xiàn)在有三個(gè)數(shù)字慨绳,需要比較大械粢薄:43662576莫瞬,594,2郭蕉。


bg2022060108.jpg

上圖是大端序排列疼邀,因?yàn)槭菑淖蟮接遗帕校匀齻€(gè)數(shù)字在右邊個(gè)位數(shù)對(duì)齊召锈。比較大小時(shí)旁振,計(jì)算機(jī)就不得不讀取每一個(gè)數(shù)的所有位,直到個(gè)位數(shù)涨岁,再進(jìn)行比較拐袜。
如果改成小端序,就是下面的排列方式梢薪。


bg2022060109.jpg

小端序是從右到左蹬铺,所以三個(gè)數(shù)字在第一位對(duì)齊。計(jì)算機(jī)就不需要讀取所有位秉撇,哪個(gè)數(shù)字先讀不到下一位甜攀,就是最小的。比如琐馆,2這個(gè)數(shù)字就沒(méi)有第二位规阀,所以讀到第二位時(shí),就知道它是最小的瘦麸。
所以谁撼,比較大小時(shí),小端序有優(yōu)勢(shì)滋饲。

乘法 (小端占優(yōu))

接下來(lái)厉碟,再看乘法操作。
乘法是逐位相乘屠缭,每一輪乘法都要向前進(jìn)位箍鼓。


bg2022060110.jpg

上圖是大端序的24165乘以3841。大端序的乘法是向左進(jìn)位勿她,也就是向左邊擴(kuò)展袄秩,必須等到每一輪的結(jié)果都出來(lái)(上例是四輪),再相加統(tǒng)一寫入內(nèi)存逢并。
如果改成小端序的乘法之剧,就不需要等待下一輪的結(jié)果,每一輪都可以直接寫入內(nèi)存砍聊。


bg2022060111.jpg

上圖是小端序的24165乘以3841背稼。小端序的乘法是向右進(jìn)位,也就是向右邊擴(kuò)展玻蝌,左邊的邊界不變蟹肘。每一輪結(jié)果寫入內(nèi)存后词疼,就不需要移動(dòng),后面有變化只需要改動(dòng)對(duì)應(yīng)的位就行了帘腹。
因此贰盗,小端序的乘法有明顯優(yōu)勢(shì)。

任意精度整數(shù) (小端占優(yōu))

上一個(gè)例子的從低位開始計(jì)算的特性阳欲,對(duì)于任意精度整數(shù)特別有用舵盈。任意精度整數(shù)又稱大整數(shù),可以存放任意大小的整數(shù)球化。
它的內(nèi)部實(shí)現(xiàn)是把整數(shù)分成一個(gè)個(gè)較小的單位秽晚,通常是 uint32(無(wú)符號(hào)32位整數(shù))或 uint64(無(wú)符號(hào)64位整數(shù)),按順序組合在一起筒愚。


bg2022060115.jpg

如果是大端序赴蝇,第一個(gè) u64 就是這個(gè)整數(shù)最大的部分。運(yùn)算時(shí)巢掺,一旦這個(gè)數(shù)發(fā)生變化句伶,需要進(jìn)位,后面的所有位都必須移動(dòng)和改寫址遇。小端序發(fā)生進(jìn)位時(shí)熄阻,往往就不需要所有位移動(dòng)。
小端序的另一個(gè)好處是倔约,如果逐字節(jié)的運(yùn)算從個(gè)位數(shù)開始(比如乘法和加法),可以從左到右依次運(yùn)算一個(gè)個(gè) u64坝初,算完上一個(gè)再讀取下一個(gè)浸剩。大端序就不行,必須讀取整個(gè)數(shù)以后再進(jìn)行運(yùn)算鳄袍。

更改類型 (小端占優(yōu))

最后一個(gè)例子是绢要,C 語(yǔ)言有一種 cast 操作,可以強(qiáng)制改變變量的數(shù)據(jù)類型拗小,比如把32位整數(shù)強(qiáng)行改變?yōu)?6位整數(shù)重罪。[圖片上傳中...(bg2022060114.jpg-7a8cc9-1701243293826-0)]

bg2022060114.jpg

上圖中,32位整數(shù)0x00000001更改為16位整數(shù)0x0001哀九,大端序是截去前面兩個(gè)字節(jié)剿配,這時(shí)指向這個(gè)地址的指針必須向后移動(dòng)兩個(gè)字節(jié)。
小端序就沒(méi)有這個(gè)問(wèn)題阅束,截去的是后面兩個(gè)字節(jié)呼胚,第一位的地址是不變的,所以指針不需要移動(dòng)息裸。

網(wǎng)絡(luò)字節(jié)序和主機(jī)字節(jié)序

網(wǎng)絡(luò)字節(jié)序:TCP/IP各層協(xié)議將字節(jié)序定義為Big Endian蝇更,即大端模式沪编,TCP/IP協(xié)議中使用的字節(jié)序是大端序,方便不同主機(jī)字節(jié)序的設(shè)備進(jìn)行網(wǎng)絡(luò)傳輸數(shù)據(jù)年扩。
主機(jī)字節(jié)序:整數(shù)在內(nèi)存中存儲(chǔ)的順序蚁廓,目前以Little Endian,即小端模式厨幻,比較普遍(不同的CPU有不同的字節(jié)序)纳令。iOS、macOS都是小端序克胳。

注意:不少文章說(shuō)macOS是大端序平绩,是錯(cuò)誤的(參考:將 macOS App 移植到 Apple 芯片 - Apple Developer )。

image 3.jpg

總結(jié):
如果需要逐位運(yùn)算漠另,或者需要到從個(gè)位數(shù)開始運(yùn)算捏雌,都是小端序占優(yōu)勢(shì)。反之笆搓,如果運(yùn)算只涉及到高位性湿,或者數(shù)據(jù)的可讀性比較重要,則是大端序占優(yōu)勢(shì)满败。
一些硬件廠商的堅(jiān)持肤频,因此在多字節(jié)存儲(chǔ)順序上始終沒(méi)有一個(gè)統(tǒng)一的標(biāo)準(zhǔn)。

如何判斷大小端算墨?

通過(guò)讀取低位地址
#include <stdio.h>

int main() {
    __uint16_t val = 0x1234;

    char a = ((char *) &val)[0]; // 低位地址
    char b = ((char *) &val)[1]; // 高位地址

    printf("a = %x\n", a);
    printf("b = %x\n", b);

    if (a == 0x34) {
        printf("小端模式\n");
    } else {
        printf("大端模式\n");
    }

    return 0;
}
利用聯(lián)合體

聯(lián)合體是一種特殊的數(shù)據(jù)結(jié)構(gòu)宵荒,聯(lián)合體中的成員變量共用同一段內(nèi)存。
我們定義一個(gè) test 聯(lián)合體净嘀,設(shè)置兩個(gè)成員變量 a 和 b报咳。

#include <stdio.h>

int main()
{
    union test {
        __uint32_t a;
        char b;
    };

    union test val;

    val.a = 0x12345678;

    printf("%x\n", val.b);

    if (val.b == 0x78) {
        printf("小端模式\n");
    } else {
        printf("大端模式\n");
    }

    return 0;
}
C 語(yǔ)言內(nèi)置宏
// 小端模式
# define LITTLE_ENDIAN  __LITTLE_ENDIAN
// 大端模式
# define BIG_ENDIAN __BIG_ENDIAN
// 當(dāng)前主機(jī)的字節(jié)序
# define BYTE_ORDER __BYTE_ORDER
#include <endian.h>

int main()
{
    if (BYTE_ORDER == LITTLE_ENDIAN) {
        printf("小端模式\n");
    } else {
        printf("大端模式\n");
    }

    return 0;
}

大小端轉(zhuǎn)換

手動(dòng)實(shí)現(xiàn)轉(zhuǎn)換邏輯
只需要將高位字節(jié)與低位字節(jié)進(jìn)行交換,就可以實(shí)現(xiàn)大小端的轉(zhuǎn)換挖藏。

int main()
{
    __uint32_t val = 0x12345678;

    unsigned char *x = (unsigned char *) &val, tmp;

    // 0x78 與 0x12 進(jìn)行交換
    tmp = x[0];
    x[0] = x[3];
    x[3] = tmp;

    // 0x56 與 0x34 交換
    tmp = x[1];
    x[1] = x[2];
    x[2] = tmp;

    // 輸出:0x78563412
    printf("0x%x\n", val);

    return 0;
}
C 語(yǔ)言內(nèi)置宏
// 轉(zhuǎn)換 16 位整數(shù)
htobe16(x)
be16toh(x)

// 轉(zhuǎn)換 32 位整數(shù)
htobe32(x)
be32toh(x)

// 轉(zhuǎn)換 64 位整數(shù)
htobe64(x)
be64toh(x)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市鸿脓,隨后出現(xiàn)的幾起案子抑钟,更是在濱河造成了極大的恐慌涯曲,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,454評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件在塔,死亡現(xiàn)場(chǎng)離奇詭異幻件,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)蛔溃,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門绰沥,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人贺待,你說(shuō)我怎么就攤上這事徽曲。” “怎么了麸塞?”我有些...
    開封第一講書人閱讀 157,921評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵秃臣,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我哪工,道長(zhǎng)奥此,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,648評(píng)論 1 284
  • 正文 為了忘掉前任雁比,我火速辦了婚禮稚虎,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘偎捎。我一直安慰自己蠢终,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,770評(píng)論 6 386
  • 文/花漫 我一把揭開白布鸭限。 她就那樣靜靜地躺著蜕径,像睡著了一般。 火紅的嫁衣襯著肌膚如雪败京。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,950評(píng)論 1 291
  • 那天梦染,我揣著相機(jī)與錄音赡麦,去河邊找鬼。 笑死帕识,一個(gè)胖子當(dāng)著我的面吹牛泛粹,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播肮疗,決...
    沈念sama閱讀 39,090評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼晶姊,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了伪货?” 一聲冷哼從身側(cè)響起们衙,我...
    開封第一講書人閱讀 37,817評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤钾怔,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后蒙挑,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體宗侦,經(jīng)...
    沈念sama閱讀 44,275評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,592評(píng)論 2 327
  • 正文 我和宋清朗相戀三年忆蚀,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了矾利。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,724評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡馋袜,死狀恐怖男旗,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情欣鳖,我是刑警寧澤察皇,帶...
    沈念sama閱讀 34,409評(píng)論 4 333
  • 正文 年R本政府宣布,位于F島的核電站观堂,受9級(jí)特大地震影響让网,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜师痕,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,052評(píng)論 3 316
  • 文/蒙蒙 一溃睹、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧胰坟,春花似錦因篇、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至吹缔,卻和暖如春商佑,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背厢塘。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工茶没, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人晚碾。 一個(gè)月前我還...
    沈念sama閱讀 46,503評(píng)論 2 361
  • 正文 我出身青樓抓半,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親格嘁。 傳聞我的和親對(duì)象是個(gè)殘疾皇子笛求,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,627評(píng)論 2 350

推薦閱讀更多精彩內(nèi)容

  • 大小端定義 大端模式(Big-endian),是指數(shù)據(jù)的高字節(jié),保存在內(nèi)存的低地址中探入,而數(shù)據(jù)的低字節(jié)狡孔,保存在內(nèi)存的...
    conowen閱讀 6,000評(píng)論 2 0
  • 內(nèi)存邏輯上是一個(gè)大的字節(jié)數(shù)組,當(dāng)存儲(chǔ)大于一個(gè)字節(jié)的數(shù)據(jù)時(shí)就有字節(jié)序的問(wèn)題新症。 大小端經(jīng)常弄混步氏,這里有種簡(jiǎn)單的記憶方法...
    lesliefang閱讀 535評(píng)論 0 1
  • 0. 一句話總結(jié) 從左向右讀(從低地址到高地址),先遇到權(quán)重“大”的就是“大”端字節(jié)序徒爹,先遇到權(quán)重“小”的就是“小...
    程序員不太冷閱讀 688評(píng)論 0 0
  • 字節(jié)序荚醒,或字節(jié)順序("Endian"、"endianness" 或 "byte-order")隆嗅,描述了計(jì)算機(jī)如何組...
    _瑾_閱讀 147評(píng)論 0 0
  • 大端和小端 big endian(大端法)是指低地址存放最高有效字節(jié)(MSB)界阁,而little endian(小端...
    右手甜蜜閱讀 2,782評(píng)論 0 0