Ada 程式設計/屬性/'位序
R'Bit_Order 是一個用於指定表示屬性,用於指定位編號的記錄表示子句(對於記錄型別)。 位排序是System.Bit_Order 型別,可以是System.Bit_Order,可以是
假設位序列被解釋為整數值。常量System.Default_Bit_Order表示平臺的本機位編號。
值得注意的是,位排序隻影響記錄表示子句的位編號,而不是其(多位元組)欄位的位元組序。[1]
儲存單元按其地址排序。讓我們看看佔用多個位元組的整數(假設位元組為 8 位)。
- 在大端(BE)機器上,整數的最高有效位元組儲存在最低地址。
- 在小端(LE)機器上,其最低有效位元組儲存在最低地址。
因此,為了能夠跨位元組邊界連續計數位,Ada 按照大端的最高有效位(MSB)0 到最低有效位(LSB)的順序計數字節內的位,而在小端上則反過來。[2]
這就是它的樣子(在大端上方便地從左到右寫,在小端上從右到左寫)
BE Byte 0 1 2 … (counting bytes, i.e. addresses, left to right; higher addresses to the right)
LE Byte … 2 1 0 (counting bytes right to left; higher addresses to the left)
MSB LSB
BE Bit 0 1 2 3 4 5 6 7 (counting bits within a byte left to right)
LE Bit 7 6 5 4 3 2 1 0 (counting bits right to left)
我們習慣了從左到右寫,但是對於小端,正如你所見,從右到左寫地址很方便。因此,在大端上,位元組和位的序列按以下方式計數
Byte 00 01 02
Bit 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 …
00 01 02 03 04 05 06 07 08 09 10 11 12 13 … (we can equally begin to count at byte 01)
為了能夠從小端連續寫入和計數,我們必須像阿拉伯語或希伯來語指令碼那樣從右到左寫(MSB 始終在左側;這似乎是所有現代指令碼中的一個全球性特徵)
Byte 02 01 00
Bit … 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00
… 13 12 11 10 09 08 07 06 05 04 03 02 01 00
在以下記錄表示中(當然,只有指定 X 的兩行中的一行可能存在)
for T use record X at 0 range 13 .. 17; -- these two lines… X at 1 range 5 .. 9; -- … are equivalent end record;
元件 X 佔用粗體所示的位。位元組編號(0 或者 1)稱為 Position,邊界稱為 First_Bit(13 或者 5)和 Last_Bit(17 或者 9);有相應的屬性'Position,'First_Bit 和'Last_Bit。(元件 X 的含義在這裡無關緊要,只有它的大小相關)。正如你所見,X 是一個跨邊界的元件。因此,將 'Bit_Order 屬性應用於具有跨邊界元件的記錄的結果取決於 Ada 的版本。
Ada 95 僅在應用於儲存單元內或專案完全填充儲存單元序列時,才定義屬性在非本機位序上的結果。透過將屬性應用於記錄,我們強制編譯器以指示的方式計數位,獨立於機器體系結構。
typeRecisrecordAat0range0 .. 5; Bat0range6 .. 7;endrecord;forRec'Bit_OrderuseHigh_Order_First;
元件 B 佔用粗體所示的位
Byte 0 Bit 0 1 2 3 4 5 6 7
此記錄的佈局在 BE 和 LE 機器上將相同,即表示是與位元組序無關的。
我們也可以這樣定義此記錄,並獲得相同的與位元組序無關的佈局
typeRecisrecordAat0range2 .. 7; Bat0range0 .. 1;endrecord;forRec'Bit_OrderuseLow_Order_First;
Byte 0 Bit 7 6 5 4 3 2 1 0
但是,以下記錄,其中 B 是跨邊界的,僅在 BE 機器上有效,即在本機位序中。
typeRecisrecordAat0range0 .. 5; Bat0range6 .. 9;endrecord;forRec'Bit_OrderuseHigh_Order_First;
Byte 0 1 Bit 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 # 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15
在 LE 機器上編譯時,編譯器會抱怨 B 佔用非連續儲存並拒絕程式碼,因為位元組序不受屬性影響(記住,下一個帶有位號 8 到 15 的位元組必須放在左側)
Byte 1 0 Bit 00 01 02 03 04 05 06 07 00 01 02 03 04 05 06 07 # 08 09 10 11 12 13 14 15 00 01 02 03 04 05 06 07
作為專案填充完整儲存單元範圍的記錄示例,請參見
typeRecisrecordAat0range0 .. 7; Bat1range0 .. 15;endrecord;forRec'Bit_OrderuseHigh_Order_First;
這在兩種體系結構上都有效,導致以下佈局
BE 0 1 2 Bit 00 01 02 03 04 05 06 07 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15
LE 2 1 0 Bit 08 09 10 11 12 13 14 15 00 01 02 03 04 05 06 07 00 01 02 03 04 05 06 07
其中 A 填充普通字型中的位,B 填充粗體字型中的位。正如你所見,在 LE 上以這種奇怪的方式計數位並不重要,因為元件 B 完全填充了它的兩個位元組。
對於本機位序,沒有變化。記錄表示規範從 Ada 83 開始就有效。只有 'Bit_Order 屬性在 Ada 95 中引入,並具有上述限制。
為了改善非本機位序的情況,Ada 2005 引入了機器標量的概念。機器標量是一個概念上的基於硬體的無符號整數,在其中計數位並按要求定位元件。
現在我們需要一個更詳細的記錄示例(相應的屬性 'Position、'First_ 和 'Last_Bit(在本機位序中)返回的值作為註釋給出;注意,返回的位號始終從元件開始的位元組開始計數)
forTuserecordIat0range0 .. 15; -- at 0 range 0 .. 15 Aat2range0 .. 12; -- at 2 range 0 .. 12 Bat2range13 .. 17; -- at 3 range 5 .. 9 Cat2range18 .. 23; -- at 4 range 2 .. 7 Dat5range0 .. 7; -- at 5 range 0 .. 7endrecord;
假設 I 是一個 16 位(有符號或無符號)整數,其他元件是某種未指定的型別,具有給定的尺寸要求。整個記錄的大小為 48。這就是它在 BE 和 LE 機器上的樣子
Byte 0 1 2 3 4 5
BE 012345678901234501234567890123456789012301234567
IIIIIIIIIIIIIIIIAAAAAAAAAAAAABBBBBCCCCCCDDDDDDDD
DDDDDDDDCCCCCCBBBBBAAAAAAAAAAAAAIIIIIIIIIIIIIIII
LE 765432103210987654321098765432105432109876543210
Byte 5 4 3 2 1 0
在下面,我們將展示為了實現表示的與位元組序無關性,我們能走多遠。結果將是,當正確使用新的 Ada 2005 功能時,我們只需要在從一種體系結構傳輸到另一種體系結構後交換位元組。
對於以下內容,我們將假設我們是在一個大端機器上,因此我們將相應的屬性附加到表示中
forTuserecordIat0range0 .. 15; Aat2range0 .. 12; Bat2range13 .. 17; Cat2range18 .. 23; Dat5range0 .. 7;endrecord;forT'Bit_OrderuseHigh_Order_First;
當這在小端機器上編譯時,所有具有相同 Position 的元件將被組合在一起並放入匹配的機器標量中。機器標量位於給定的 Position 處,但在內部,位從相反方向計數。
讓我們以第一個元件 I 為例。它使用 16 位,因此可以使用 16 位機器標量。它位於位元組 0 處,但在內部,編譯器將從高位端計數。這就是它的樣子(NNBO - 非本機位序)
IIIIIIIIIIIIIIII NNBO 0123456789012345 Byte 5 4 3 2 1 0
現在到下一個 Position 2。相應的元件 A、B、C 總共使用三個位元組,因此需要一個 32 位機器標量。它位於位元組 2 處,在內部計數將再次從相反方向開始。這就是它的樣子
IIIIIIIIIIIIIIII NNBO 012345678901234567890123456789010123456789012345 Byte 5 4 3 2 1 0
位計數從位元組 5 的最高有效位開始,一直持續到位元組 2 的最低有效位。元件 A、B、C 在此標量內部根據各自的範圍進行定位。因此,我們得到了以下佈局
AAAAAAAAAAAAABBBBBCCCCCC IIIIIIIIIIIIIIII NNBO 012345678901234567890123456789010123456789012345 Byte 5 4 3 2 1 0
我們立即看到與元件 D 的衝突,它的範圍已被 A 佔用,編譯器當然會報錯並拒絕程式碼。解決方案很簡單:只需將 D 的位置從 5 更改為 (在 BE 上) 等效行,如下所示
forTuserecordIat0range0 .. 15; Aat2range0 .. 12; Bat2range13 .. 17; Cat2range18 .. 23; --D at 5 range 0 .. 7; Dat2range24 .. 31;endrecord;forT'Bit_OrderuseHigh_Order_First;
並且,鼓聲響起,在 LE 上,我們現在有(為了比較,還給出了本機佈局)
AAAAAAAAAAAAABBBBBCCCCCCDDDDDDDDIIIIIIIIIIIIIIII
NNBO 012345678901234567890123456789010123456789012345
Byte 5 4 3 2 1 0
IIIIIIIIIIIIIIIIAAAAAAAAAAAAABBBBBCCCCCCDDDDDDDD
BE 012345678901234501234567890123456789012345678901
Byte 0 1 2 3 4 5
在非本機位順序中,由相應屬性“Position”、“First_”和“Last_Bit”返回的值與記錄規範中給出的值完全一致。
作為一項額外服務,GNAT 的編譯輸出將為您提供在機器標量中以本機位順序計算的值
range
"I" 0 .. 15
"A" 19 .. 31
"B" 14 .. 18
"C" 8 .. 13
"D" 0 .. 7
AAAAAAAAAAAAABBBBBCCCCCCDDDDDDDDIIIIIIIIIIIIIIII
NNBO 012345678901234567890123456789010123456789012345
LE 109876543210987654321098765432105432109876543210
Byte 5 4 3 2 1 0
這是我們在當前 Ada 標準下所能達到的極限。
讓我們將此記錄的值從本機大端機傳輸到小端機。為了演示目的,跨邊界專案的最高位部分顯示為大寫,最低位部分顯示為小寫。
IIIIIIIIiiiiiiiiAAAAAAAAaaaaaBBBbbCCCCCCDDDDDDDD BE 012345678901234501234567890123456789012345678901 Byte 0 1 2 3 4 5
位元組將按給定順序傳輸。由於位順序屬性不會在傳輸後重新排序位元組,因此在目標機器上,我們將以亂序接收資料
DDDDDDDDbbCCCCCCaaaaaBBBAAAAAAAAiiiiiiiiIIIIIIII NNBO 012345678901234567890123456789010123456789012345 Byte 5 4 3 2 1 0
我們所要做的就是交換位元組 0↔1、2↔5、3↔4,以達到預期的結果
AAAAAAAAaaaaaBBBbbCCCCCCDDDDDDDDIIIIIIIIiiiiiiii NNBO 012345678901234567890123456789010123456789012345 Byte 5 4 3 2 1 0
以下兩組表示子句在任何機器/編譯器(Ada 2005 及更高版本)中指定了相同的暫存器佈局
typeDevice_RegisterisrecordReady : Status_Flag; Error : Error_Flag; Data : Unsigned_16;endrecord;forDevice_RegisteruserecordReadyat0range0 .. 0; Errorat0range1 .. 1; -- Reserved bits Dataat0range16 .. 31;endrecord;forDevice_Register'Sizeuse32;forDevice_Register'Bit_OrderuseSystem.Low_Order_First;pragmaAtomic (Device_Register);
如果位順序修改,則必須反轉記錄表示子句中所有元素的位編號
typeDevice_RegisterisrecordReady : Status_Flag; Error : Error_Flag; Data : Unsigned_16;endrecord;forDevice_RegisteruserecordReadyat0range31 .. 31; -- Bit numbering has changed Errorat0range30 .. 30; -- Bit numbering has changed -- Reserved bits Dataat0range0 .. 15; -- Bit numbering has changed (but byte order is not affected)endrecord;forDevice_Register'Sizeuse32;forDevice_Register'Bit_OrderuseSystem.High_Order_First; -- Reverse bit orderpragmaAtomic (Device_Register);
兩者可以在同一臺機器上互換使用。但請注意,在兩臺具有不同位元組序的機器中資料欄位將具有本機位元組序,而與表示子句中指定的位順序無關。
'Bit_Order 屬性並非旨在將資料在大小端機器之間轉換(它影響位編號,而不是位元組順序)。當指定非本機位順序時,編譯器不會生成程式碼來重新排序多位元組欄位。[3][4][5]
- ↑ 請注意,當 ARM 在 'Bit_Order 屬性的定義中談論“大端”和“小端”時,它實際上指的是位位元組序,而不是位元組位元組序。(如今,術語位元組序通常保留用於討論位元組順序,儘管它也可以用於位編號。)因此,在這種情況下,當 ARM 說“小端”時,它指的是“LSB 0”,而當它說“大端”時,它與“MSB 0”相同:
«High_Order_First(在口語中稱為“大端”)表示儲存元素的第一個位(位 0)是最重要的位(將表示元件的位序列解釋為無符號整數)。Low_Order_First(在口語中稱為“小端”)表示相反:第一個位是最不重要的位。» [LRM, §13.5.3(2)]
- ↑ ISO/IEC 8652:1987. "13.4 Record Representation Clauses". Ada 83 Reference Manual.
The range defines the bit positions of the storage place, relative to the storage unit. The first storage unit of a record is numbered zero. The first bit of a storage unit is numbered zero. The ordering of bits in a storage unit is machine_dependent and may extend to adjacent storage units.
{{cite book}}: Unknown parameter|chapterurl=ignored (|chapter-url=suggested) (help) - ↑ AI95-00133-01 (1996-05-07). "Controlling bit ordering". Class: binding interpretation. Ada Rapporteur Group.
Bit_Order clauses are concerned with the numbering of bits and not concerned with data flipping interoperability.
- ↑ ISO/IEC 8652:2007. "13.5.3 Bit Ordering (9/2)". Ada 2005 Reference Manual. Retrieved 2008-06-02.
Bit_Order clauses make it possible to write record_representation_clauses that can be ported between machines having different bit ordering. They do not guarantee transparent exchange of data between such machines.
{{cite book}}: Unknown parameter|chapterurl=ignored (|chapter-url=suggested) (help) - ↑ Thomas Quinot (2013). "Gem #140: Bridging the Endianness Gap". AdaCore. Retrieved 2013-01-31.
the order in which the bytes that constitute machine scalars are written to memory is not changed by the Bit_Order attribute -- only the indices of bits within machine scalars are changed.
{{cite web}}: Unknown parameter|month=ignored (help)
據作者所知,記錄表示子句是 Ada 語言的獨特功能,因此不需要在其他程式語言中使用類似於屬性 'Bit_Order 的功能。在其他程式語言中,通常的做法是顯式使用掩碼和位運算,因此必須始終使用本機位編號。
- 13.5.3 位排序 (帶註釋)
- 附錄 K 語言定義屬性 (帶註釋)
- Ada 95: 13.1 資料表示
- Ada 2005: 9.2.1 與原始 Ada 95 的不相容性
- Norman H. Cohen (1994). "與位元組序無關的記錄表示子句" (PDF). ACM SIGAda Ada Letters. New York, NY, USA: Association for Computing Machinery. XIV (1): 27–29. ISSN 1094-3641. 檢索於 2008-12-20.
- Randal P. Andress (2005). "對最外層 Ada 記錄物件進行整體位元組反轉以實現通訊資料型別的位元組序獨立性" (PDF). ACM SIGAda Ada Letters. New York, NY, USA: Association for Computing Machinery. XXV (3): 19–27. ISSN 1094-3641. 檢索於 2008-12-20.
