日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Endian Bitfiled

發布時間:2025/4/14 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Endian Bitfiled 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
Endianess是個比較tricky的問題,特別是當數據在不同類型間轉換時。?

先看看在一臺32位的little-endian機器上,以下代碼的行為:?
C代碼??
  • #include?<stdio.h>?//?memcpy??
  • #include?<stdlib.h>?//?printf??
  • ??
  • typedef?struct?{??
  • ????char?a;??
  • ????char?b;??
  • ????char?c;??
  • ????char?d;??
  • }?st;??
  • ??
  • void?main()?{??
  • ????st?s;??????
  • ????memcpy(&s,?"RednaxelaFX",?sizeof(s));??
  • ????printf("sizeof(s)?=?%d\n",?sizeof(s));?//?4??
  • ????printf("%X\n",?s);?//?6E646552??
  • ????printf("%c,?%c,?%c,?%c\n",?s.a,?s.b,?s.c,?s.d);?//?R,?e,?d,?n??
  • }??

  • 在32位x86上有4字節的對齊,正好4個char就是4字節于是st中沒有padding。可以看到,struct中的成員是按聲明順序從低地址到高地址排列的。C99規范的6.7.2.1規定了這點。一個數組是一塊連續的、有序的空間,而一個字符串是一個char數組,所以可以看到s.a, s.b, s.c, s.d跟字符串(char數組)的開頭4個字符(字節)對應:'R' 'e' 'd' 'n'(52 65 64 6E)分成4段:(| 52 | 65 | 64 | 6E |)分別對應s.a到s.d。?
    但將該struct解釋為一個32位的整型,并以十六進制的方式顯示出來,則會發現字節的順序顛倒了過來:?
    原本'R' 'e' 'd' 'n'的十六進制表示是52 65 64 6E;轉換為一個整型之后,則變為0x6E646552,字節的順序正好反了過來。注意是字節而不是位的順序反了過來,字節內的位的順序依然保持不變。?

    這體現了little-endian機器上對數據解釋方式的不同。在內存中的數據在參與運算前會先加載到寄存器中,字節序(endian)的差異就在這一步上:如果是big-endian,則讀到寄存器的數據的字節序跟內存中的一樣;反之如果是little-endian,則讀到寄存器的數據的字節序跟內存中的相反。?
    說“相反”,到底在多大的范圍內“相反”呢?這就要看運算涉及的數據類型(特指原始數據類型dword/word/byte等)的寬度了:數據類型有多寬,就在多少字節間需要將字節順序反轉過來。如果上面的st中不是含有4個char而是含有兩個short,那么在32位x86上的執行結果就會變成:?
    C代碼??
  • #include?<stdio.h>??
  • #include?<stdlib.h>??
  • ??
  • typedef?struct?{??
  • ????short?a;??
  • ????short?b;??
  • }?st;??
  • ??
  • void?main()?{??
  • ????st?s;??????
  • ????memcpy(&s,?"RednaxelaFX",?sizeof(s));??
  • ????printf("sizeof(s)?=?%d\n",?sizeof(s));?//?4??
  • ????printf("%X\n",?s);?//?6E646552??
  • ????printf("%X,?%X\n",?s.a,?s.b);?//?6552,?6E64??
  • }??

  • 也就是把'R' 'e' 'd' 'n'(52 65 64 6E)分成兩段(| 52 65 | 64 6E |),然后將字節的順序反轉過來解釋為整型數字(0x6552,0x6E64)。直接解釋為一個32位整型的時候,'R' 'e' 'd' 'n'(52 65 64 6E)分成一段(| 52 65 64 6E |),并在這一段內反轉字節順序得到0x6E646552。?
    前面用4個char為例時,因為每個單元的數據本身就只有1字節,反轉不反轉沒有差別,所以無論是在big-endian還是在little-endian機器上執行的結果都會是一樣的。?

    再次強調:字節序只影響解釋數據時字節間的順序,不影響每個字節內的位的順序。?

    ===========================================================================?

    那么結合C struct里的bitfield又會怎樣的??
    還是在C99規范的6.7.2.1節里,規范規定了可以對struct中的field顯式指定寬度(以bit為單位);顯式指定了寬度的field被稱為bit-field。規范中同一小節中的第10點有如下說明:?
    引用 An implementation may allocate any addressable storage unit large enough to hold a bitfield. If enough space remains, a bit-field that immediately follows another bit-field in a structure shall be packed into adjacent bits of the same unit. If insufficient space remains, whether a bit-field that does not fit is put into the next unit or overlaps adjacent units is implementation-defined.?The order of allocation of bit-fields within a unit (high-order to low-order or low-order to high-order) is implementation-defined.?The alignment of the addressable storage unit is unspecified.
    根據該說明,規范留下了許多故意未定義的地方,包括紅字標出的:同一單元內排列bit-field的順序未定義。所以我們無法根據規范確定同一組bit-field到底哪個在前哪個在后。?

    雖然如此,具體到某個機器上某個編譯器所編譯出來的結果還是需要解釋的。這里以32位x86搭配VC9/GCC3.4為例,這兩個編譯器在這個例子中行為一樣。觀察下面代碼?
    C代碼??
  • #include?<stdio.h>??
  • #include?<stdlib.h>??
  • ??
  • typedef?struct?{??
  • ????int?a:5;??
  • ????int?:2;??
  • ????int?b:2;??
  • }?bitstruct;??
  • ??
  • void?main()?{??
  • ????bitstruct?b;??
  • ????memcpy(&b,?"RednaxelaFX",?sizeof(b));??
  • ????printf("sizeof(b)?=?%d\n",?sizeof(b));?//?4??
  • ????printf("%X\n",?b);?//?6E646552??
  • ????printf("%X,?%X\n",?b.a,?b.b);?//?FFFFFFF2,?FFFFFFFE??
  • ????printf("%d,?%d\n",?b.a,?b.b);?//?-14,?-2??
  • }??

  • 例子中的bitstruct中有3個bit-field,第一個是名字為a的5位帶符號整型,第二個是匿名的2位帶符號整形,第三個是名字為b的2位帶符號整型,加起來一共是9位,但32位x86上有4字節對齊的要求,所以經過padding后,bitstruct的寬度是4字節(32位)。從存儲單元的角度看,1個dword(32位)就是1個存儲單元,bitstruct中包含一個存儲單元,并且其中的3個成員都在這個存儲單元中。bitstruct.a占有“前”5位,匿名field占有緊接著的2位,然后bitstruct.b占有接下來的2位(注意“前”到底是從哪邊開始在規范中并沒有定義)。?
    這個寬度與前面兩個例子中的st一樣,當然執行到printf("%X\n", b);這句的時候結果也一樣。關鍵就在這其中的bit-field是如何解釋成-14和-2的。?

    從結果來看,可以知道:bitstruct的3個field都在同一個存儲單元內,并且由于x86是little-endian的,數據從內存讀到寄存器之后字節序就反了過來,高位字節到低位字節的順序是“從右向左”;對應的,解釋bitstruct中的各field時也從右向左來讀。?
    寄存器中的b:?
    'n' 'd' 'e' 'R'?
    6E? 64? 65? 52?
    用二進制表示就是:?
    01101110 01100100 01100101 01010010?
    “從右向左”來數寬度,最靠右的5位是b.a,其左邊2位是匿名field,然后再左邊2位是b.b。注意:從右向左數的是寬度,不是數據內容的位的順序。?
    那么就有(二進制):?
    b.a: 10010?
    b.b: 10?
    由于這兩個field是帶符號的整型,讀出來的時候需要做帶符號擴展到一個int,于是它們就分別擴展到(十六進制):?
    b.a: FFFFFFF2?
    b.b: FFFFFFFE?
    換回用普通的帶符號十進制表示也就是:?
    b.a: -14?
    b.b: -2?

    如果還是覺得沒轉過腦筋來,那么這樣看:實際由編譯器編譯出來會像這樣:(只是用于表現概念)?
    C代碼??
  • bitstruct?b;??
  • int?temp;??
  • //?assign?to?b,?make?some?changes,?whatever...??
  • ??
  • //?here's?what's?supposed?to?be?"temp?=?b.a":??
  • temp?=?(int)b;??
  • temp?<<=?27;?//?27?==?32?-?5??
  • temp?>>=?27;?//?27?==?32?-?5??
  • ??
  • //?and?here's?what's?supposed?to?be?"temp?=?b.b":??
  • temp?=?(int)b;??
  • temp?<<=?23;?//?23?==?32?-?5?-?2?-?2??
  • temp?>>=?30;?//?30?==?32?-?2??

  • 注意:?
    1. temp = (int)b;這里,把bitstruct里的數據解釋為單個32位整型時,little-endian的作用就體現出來了;在4個字節的范圍內字節的順序需要反轉過來。?
    2. 左移27位再右移27位與直接拿0x01F來做mask是不等價的:前者的右移是帶符號的,而后者直接把符號掩蓋掉了。?

    --------------------------------------------------------------------------?

    需要在說明一次,規范中并沒有規定一定要按照這個順序,只是這個例子選用的機器+編譯器組合中有這樣的行為而已。bit-field在存儲單元內安排的順序如何從一般程序中是看不出來的,因為:?
    引用 The unary & (address-of) operator cannot be applied to a bit-field object; thus, there are no pointers to or arrays of bit-field objects.
    無法獲得單一bit-field的地址(但可以獲得這個bit-field所在的存儲單元的起始地址),所以一般程序無從得知到底bit-field是從哪邊開始存的;編譯器會生成合適的位移指令序列來得到bit-field的值/對bit-field賦值。程序不應該依賴于bit-field存儲的順序。 《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀

    總結

    以上是生活随笔為你收集整理的Endian Bitfiled的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。