簡體   English   中英

為什么禁止非const引用位域?

[英]Why are non-const references to bitfields prohibited?

C ++ 11中的第9.6 / 3節非常清楚:“非const引用不應綁定到位字段。” 這項禁令背后的動機是什么?

我知道不可能將引用直接綁定到位域。 但如果我宣布這樣的話,

struct IPv4Header {
  std::uint32_t version:4,         // assumes the IPv4 Wikipedia entry is correct
                IHL:4,
                DSCP:6,
                ECN:2,
                totalLength:16;
};

為什么我不能這樣說呢?

IPv4Header h;

auto& ecn = h.ECN;

我希望底層代碼實際綁定到包含我感興趣的位的整個std::uint32_t ,並且我希望讀取和寫入操作生成代碼以進行適當的屏蔽。 結果可能是大而慢,但在我看來它應該工作。 這與標准表示對const位域的引用的工作方式一致(同樣來自9.6 / 3):

如果類型為const T&的引用的初始值設定項是引用位字段的左值,則引用綁定到初始化的臨時值以保存位字段的值; 引用不直接綁定到位字段。

這表明寫入位域是問題,但我不知道它是什么。 我認為必要的屏蔽可能會在多線程代碼中引入競爭,但是,根據1.7 / 3,非零寬度的相鄰位域被認為是用於多線程的單個對象。 在上面的示例中, IPv4Header對象中的所有位域都將被視為單個對象,因此根據定義,在讀取其他字段時嘗試修改字段的多線程代碼已經很有效。

我顯然遺漏了一些東西。 它是什么?

您不能將非const引用帶到位域,原因與您不能使用&地址相同:它的實際地址不一定與char對齊, char在定義上是C ++摘要中最小的可尋址內存單位機。 您可以對它進行const引用,因為編譯器可以自由復制該值,因為它不會被突變。

考慮單獨編譯的問題。 一個帶有const uint32_t&const uint32_t&需要使用相同的代碼來操作任何const uint32_t& 如果普通值和位域值需要不同的寫行為,則該類型不會編碼足夠的信息,以使函數在兩者上都能正常工作。

由於指針不能指向位字段,因此非const引用不能綁定到位字段。

雖然沒有指定引用是否占用存儲,但很明顯,在非平凡的情況下,它們被偽裝成指針實現,並且這種引用的實現是由該語言的作者“預期”實現的。 就像指針一樣,引用必須指向可尋址的存儲單元。 將非const引用綁定到不可尋址的存儲單元是不可能的。 由於非const引用需要直接綁定,因此非const引用不能綁定到位字段。

產生指向位字段的指針/引用的唯一方法是實現某種“超級指針”,除了存儲器中的實際地址外,它還包含某種位偏移和位寬信息,為了告訴寫代碼要修改哪些位。 請注意,此附加信息必須存在於所有數據指針類型中,因為C ++中沒有“指向/引用位域”的類型。 這基本上等同於實現更高級別的存儲尋址模型,與底層OS /硬件平台提供的尋址模型完全脫節。 C ++語言從不打算從純粹的效率考慮中要求從底層平台那種抽象。

一種可行的方法是引入一個單獨的指針/引用類別,例如“指向/指向位域的引用”,它將具有比普通數據指針/引用更復雜的內部結構。 這些類型可以從普通數據指針/引用類型轉換,但不能相反。 但它似乎不值得。

在實際情況中,當我必須處理打包成比特和比特序列的數據時,我通常更喜歡手動實現比特字段並避免語言級別的比特字段。 位字段的名稱是編譯時實體,不可能選擇任何類型的運行時。 當需要運行時選擇時,更好的方法是聲明一個普通的uint32_t數據字段並手動管理其中的各個位和位組。 這種手動“位字段”的運行時選擇很容易通過掩碼和移位來實現(兩者都可以是運行時值)。 基本上,這接近於上述“超級指針”的手動實現。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM