簡體   English   中英

為什么普通變量不允許位域?

[英]Why aren't bitfields allowed with normal variables?

我想知道為什么位域適用於聯合/結構,而不適用於像intshort這樣的普通變量。
這有效:

struct foo {
    int bar : 10;
};

但這失敗了:

int bar : 10; // "Expected ';' at end of declaration"

為什么此功能僅在聯合/結構中可用,而在變量中不可用? 技術上不一樣嗎?


編輯:

如果允許,您可以創建一個具有 3 個字節的變量,而無需每次都使用 struct/union 成員。 這就是我對結構的處理方式:

struct int24_t {
    int x : 24 __attribute__((packed));
};

struct int24_t var; // sizeof(var) is now 3
// access the value would be easier:
var.x = 123;

這是一個主觀問題,“為什么規范這么說?” 但我會盡力而為。

函數中的變量通常具有“自動”存儲,而不是其他持續時間之一(靜態持續時間、線程持續時間和分配的持續時間)。

在結構中,您明確定義了某個對象的內存布局。 但是在函數中,編譯器會以某種未指定的方式自動為變量分配存儲空間。 這里有一個問題: x在堆棧上占用了多少字節?

// sizeof(unsigned) == 4
unsigned x;

它可能占用 4 個字節,也可能占用 8 個、12 個或 0 個字節,或者它可以同時放置在三個不同的寄存器中,或者堆棧和一個寄存器中,或者它可以在堆棧上放置四個位置.

關鍵是編譯器正在為您進行分配。 由於您沒有進行堆棧的布局,因此不應指定位寬。

擴展討論:位域實際上有點特殊。 該規范指出相鄰的位域被打包到同一個存儲單元中。 位域實際上不是對象。

  1. 你不能sizeof()一個位域。

  2. 你不能malloc()一個位域。

  3. 你不能&addressof位域。

所有這些事情你都可以用 C 中的對象來做,但不能用位域來做。 位域是一種特殊的東西,只為結構而生,沒有其他地方。

關於int24_t (更新):它適用於某些架構,但不適用於其他架構。 它甚至沒有一點便攜性。

typedef struct {
    int x : 24 __attribute__((packed));
} int24_t;

在 Linux ELF/x64、OS X/x86、OS X/x64 上, sizeof(int24_t) == 3 但在 OS X/PowerPC 上, sizeof(int24_t) == 4

請注意,GCC 為加載int24_t生成的代碼基本上等同於:

int result = (((char *) ptr)[0] << 16) |
             (((unsigned char *) ptr)[1] << 8) |
             ((unsigned char *)ptr)[2];

這是 x64 上的 9 條指令,只是為了加載單個值。

結構或聯合的成員在其存儲位置之間存在關系。 由於對布局的嚴格限制,編譯器無法以巧妙的方式重新排序或打包它們以節省空間; 基本上,編譯器在布局結構方面的唯一自由是添加超出對齊所需數量的額外填充的自由。 位域允許您通過承諾 (1) 您不需要這些成員的地址,以及 (2) 您不需要存儲某個有限范圍之外的值,從而手動給予編譯器更多的自由來緊密地打包信息。

如果您談論的是單個變量而不是結構成員,那么在抽象機器中,它們的存儲位置之間沒有關系 如果它們是函數中的局部自動變量並且它們的地址永遠不會被占用,那么編譯器可以隨意將它們保存在寄存器中或將它們打包在內存中。 手動向編譯器提供此類提示幾乎沒有好處。

因為意義不大。 位域聲明用於在struct字段之間共享和重新組織位。 如果您沒有成員,只有一個大小恆定的變量(這是實現定義的),例如,將幾乎肯定為 8 位寬的char聲明為 1 位或 12 位變量是矛盾的.

如果一個結構QBLOB包含將四個 2 位位域組合成一個字節,則每次使用該結構時,與僅包含四個unsigned char類型字段的結構相比,每次使用該結構都將節省三個字節。 如果聲明一個數組QBLOB myArray[1000000] ,這樣的數組將只占用 1,000,000 個字節; 如果 QBLOB 是一個具有四個unsigned char字段的結構,它將需要多 3,000,000 個字節。 因此,使用位域的能力可以代表大量的內存節省。

相比之下,在大多數體系結構上,將簡單變量聲明為最佳大小的位域類型與將其聲明為最小的合適標准整數類型相比,最多可以節省 15 位。 由於訪問位域通常比訪問標准整數類型的變量需要更多的代碼,因此很少有將單個變量聲明為位域會帶來任何好處的情況。

不過,這一原則有一個值得注意的例外:某些架構包含的功能可以比讀寫字節更有效地設置、清除和測試單個位。 某些此類架構的編譯器包含bit類型,並將該類型的八個變量打包到存儲的每個字節中。 此類變量通常僅限於靜態或全局范圍,因為處理它們的專用指令可能僅限於使用某些內存區域(鏈接器可以確保將任何此類變量放置在它們必須去的地方)。

所有對象必須占用一個或多個連續的字節或字,但位域不是對象 它只是一種用戶友好的方式來屏蔽單詞中的位。 包含位域的struct必須占用整數個字節或字; 編譯器只是添加了必要的填充,以防位域大小加起來不是一個完整的字。

沒有技術原因不能擴展 C 語法來定義結構(AFAIK)之外的位域,但是對於所涉及的工作量,它們的實用性值得懷疑。

暫無
暫無

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

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