2010-11-28 28 views
19

我對C沒有完全確定,但C++允許0長度的未命名位域。例如:零長度位域的實際應用

struct X 
{ 
    int : 0; 
}; 
  • 問題一:怎麼看的實際用途想到什麼?
  • 問題二:你知道哪些現實世界的實際用途(如果有的話)?

編輯冰犯罪的回答後,例如

編輯: OK,由於目前的答案,我現在知道了理論上的目的。但問題是關於實際用途,使他們仍然持有:)

+1

C99允許零長度數組更好地支持動態大小的結構。 – falstro 2010-11-28 14:02:15

+0

@roe:是的,它相當於0長度的動態分配數組,它非常有用。我認爲這裏的問題是位域長度必須是編譯時常量。 – 2010-11-28 14:03:32

+6

@roe:您的評論不正確。 C **不允許在任何版本的標準中使用** char a [0];`另一方面,C99中的結構中允許使用`char a [];`;它被稱爲靈活的數組成員,並且必須出現在最後。 `char a [];`是** not ** a`簡寫爲`char a [0];`「。 – 2010-11-28 14:57:41

回答

26

您使用零長度位域作爲一種拙劣的方式讓編譯器佈局結構以匹配某些外部需求,無論是其他編譯器還是架構的佈局概念(跨平臺數據結構,如in二進制文件格式)或比特級標準的要求(網絡數據包或指令操作碼)。

一個現實世界的例子是NeXT將xnu內核從摩托羅拉68000(m68k)架構移植到i386架構。 NeXT有一個m68k版本的內核。當他們將其移植到i386時,他們發現i386的對齊要求與m68k不同,m68k機器和i386機器不同意NeXT供應商特定BOOTP結構的佈局。爲了使i386結構佈局與m68k一致,他們添加了一個長度爲零的未命名位域,以強制NV1結構/ nv_U聯合爲16位對齊。

下面是從Mac OS X 10.6.5 XNU源代碼的相關部分:

/* from xnu/bsd/netinet/bootp.h */ 
/* 
* Bootstrap Protocol (BOOTP). RFC 951. 
*/ 
/* 
* HISTORY 
* 
* 14 May 1992 ? at NeXT 
* Added correct padding to struct nextvend. This is 
* needed for the i386 due to alignment differences wrt 
* the m68k. Also adjusted the size of the array fields 
* because the NeXT vendor area was overflowing the bootp 
* packet. 
*/ 
/* . . . */ 
struct nextvend { 
    u_char nv_magic[4]; /* Magic number for vendor specificity */ 
    u_char nv_version; /* NeXT protocol version */ 
    /* 
    * Round the beginning 
    * of the union to a 16 
    * bit boundary due to 
    * struct/union alignment 
    * on the m68k. 
    */ 
    unsigned short :0; 
    union { 
    u_char NV0[58]; 
    struct { 
     u_char NV1_opcode; /* opcode - Version 1 */ 
     u_char NV1_xid; /* transcation id */ 
     u_char NV1_text[NVMAXTEXT]; /* text */ 
     u_char NV1_null; /* null terminator */ 
    } NV1; 
    } nv_U; 
}; 
19

標準(9.6/2)僅允許0長度位字段作爲特例

作爲一個特殊的情況下,未命名的 寬度爲零的位字段 指定在分配單元 邊界處的下一個 位字段的對齊。 僅在聲明 未命名位字段時, 常數表達式的值等於 爲零

雖然我從來沒有在實際的代碼中遇到它,但在這個引用中只描述了唯一的用法。


爲了記錄在案,我只是想下面的代碼VS 2010下:

struct X { 
    int i : 3, j : 5; 
}; 

struct Y { 
    int i : 3, : 0, j : 5; // nice syntax huh ? 
}; 

int main() 
{ 
    std::cout << sizeof(X) << " - " << sizeof(Y) << std::endl; 
} 

我的機器上輸出的確是:4 - 8

5

這是從MSDN和沒有標記爲微軟特定,所以我想這是常見的C++標準:

下一比特字段的寬度0力對準的未命名的位字段到下一個類型邊界,其中類型是成員的類型。

6
struct X { int : 0; }; 

是C.

見(重點煤礦)未定義的行爲:

(C99,6.7.2.1p2)「struct-or-union-specifier中存在struct-declaration-list聲明一個新類型,在一個轉換單元中struct-聲明列表是結構或聯盟成員的一系列聲明。 如果結構聲明列表中沒有名稱的成員,該行爲是未定義

(C11具有同樣的措辭。)

您可以使用一個無名位字段與0寬度,但不如果在結構上沒有其它命名構件

,例如:

struct W { int a:1; int :0; }; // OK 
struct X { int :0; };   // Undefined Behavior 

順便說爲第二個聲明,gcc使用-pedantic發佈診斷(C標準未要求)。

在另一方面:

struct X { int :0; }; 

在GNU C中定義它用於例如通過Linux內核(include/linux/bug.h)使用以下宏,如果該條件爲真,迫使編譯錯誤:

#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); }))