2012-12-19 64 views
4

我想知道爲什麼位域可以與工會/結構一起工作,但不能和像intshort這樣的正常變量一起工作。
這工作:爲什麼正常變量不允許位域?

struct foo { 
    int bar : 10; 
}; 

但這種失敗:

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

爲什麼這個功能僅在工會/結構,而不是與變量可用?技術不一樣嗎?


編輯:

如果將允許你能與例如3個字節的變量,而不每次使用結構/聯合成員。這是我如何與一個結構:

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; 
+4

呃,因爲它沒有意義。 – 2012-12-19 18:13:56

+3

@ H2CO3這並不能幫助回答這個問題。你想說明爲什麼它在一個案件中是有道理的,但不是另一個案件中的道理? (我相信你有理由發表你的評論,我只是想知道它是什麼。) –

+2

@ap。當然。位域用於在結構的成員之間分割/共享位。如果只有一個變量,並且沒有(連續的)字段(在結構中),這是不合理的/有意義的。 – 2012-12-19 18:16:56

回答

7

這是一個主觀問題,「規範爲什麼這麼說?」但我會把它拍下來。

與其他持續時間(靜態持續時間,線程持續時間和分配持續時間)相比,函數中的變量通常具有「自動」存儲。

在一個結構中,你明確地定義了一些對象的內存佈局。但是在函數中,編譯器自動以某種未指定的方式將變量分配給變量。下面是一個問題: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/64,OS X/86,OS X/64,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分的說明,只是加載一個值。

+0

sizeof(int24_t)將是3 – vromanov

+0

@vromanov:錯了。在通用體系結構上使用上面的聲明'sizeof(int24_t)== 4'。 –

+0

請做測試!在Centos 6.5 x64(gcc)sizeof(int24_t)== 3 – vromanov

1

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

3

結構或聯合的成員之間有其存儲位置之間的關係。由於嚴格限制佈局,編譯器無法以聰明的方式對其進行重新排序或打包;基本上編譯器在佈局結構方面的唯一自由就是可以自由添加超出對齊所需的額外填充量。 Bitfields允許您手動通過承諾(1)您不需要這些成員的地址,並且(2)您不需要將值存儲在特定的有限範圍之外。

如果你談論的是單個變量而不是結構成員,那麼在抽象機器中他們有它們的存儲位置之間沒有關係。如果它們是函數中的本地自動變量,並且它們的地址永遠不會被獲取,那麼編譯器可以自由地將它們保存在寄存器中,或者將它們包裝在內存中,但它喜歡。手動向編譯器提供這些提示幾乎沒有任何好處。

0

如果一個人有一個結構QBLOB其中包含結合了四個2位位域到單個字節,每一個結構被用作與簡單包含unsigned char類型的四個字段的結構體相比,將代表三個字節的時間節省。如果聲明一個數組QBLOB myArray[1000000],這樣一個數組只需要1,000,000字節;如果QBLOB是一個包含四個unsigned char字段的結構,則它將需要更多300,000字節。因此,使用位域的能力可能會節省大量內存。相比之下,在大多數體系結構中,聲明簡單變量爲最佳大小的位域類型與聲明它爲最小合適的標準整數類型相比,可以節省至多15位。由於訪問位域通常比訪問標準整型變量需要更多的代碼,因此很少有情況下將各個變量聲明爲位域會提供任何優勢。但是,這個原理有一個明顯的例外:一些體系結構包括可以設置,清除和測試各個位的功能,這些功能比讀取和寫入字節更有效。某些此類體系結構的編譯器包括bit類型,並將該類型的八個變量打包到每個存儲字節中。這些變量通常侷限於靜態或全局範圍,因爲處理它們的專用指令可能會限制使用某些內存區域(鏈接器可以確保將這些變量放在必須去的地方)。

0

全部對象必須佔用一個或多個連續字節或字,但位域不是對象;它只是一個用戶友好的掩飾單詞中位的方法。包含位域的struct必須佔用整數個字節或字;編譯器只需添加必要的填充以避免位域大小不合計爲完整的單詞。

有沒有技術爲什麼你不能擴展C語法來定義結構(AFAIK)之外的位域,但它們對涉及的工作量是有問題的。

相關問題