2010-11-28 8 views
19

Ich bin nicht ganz sicher über C, aber C++ erlaubt unbenannte Bit-Felder von 0 Länge. Zum Beispiel:Praktische Verwendung von Null-Länge-Bitfeldern

struct X 
{ 
    int : 0; 
}; 
  • Frage ein: Was für praktische Anwendungen dieser kann Sie denken?
  • Frage zwei: Was praktische Praxis (wenn überhaupt) ist Ihnen bekannt?

Herausgegeben das Beispiel nach Antwort des Eis-Verbrechen

Edit: OK, dank der aktuellen Antworten weiß, dass ich nun den theoretischen Zweck. Aber die Fragen sind über praktische Anwendungen, so dass sie immer noch :) halten

+1

C99 ermöglicht Arrays mit einer Länge von Null, um dynamisch große Strukturen besser zu unterstützen. – falstro

+0

@roe: Ja, nun, es ist das Äquivalent von dynamisch zugewiesenen Arrays mit einer Länge von 0, die wirklich nützlich sind. Ich denke, dass das Problem hier ist, dass die Bitfeldlänge eine Kompilierzeitkonstante sein muss. –

+6

@roe: Ihr Kommentar ist falsch. C ** erlaubt ** 'char a [0];' in keiner Version des Standards. Auf der anderen Seite ist 'char a [];' in Strukturen in C99 erlaubt; Es heißt ein flexibles Array-Mitglied und muss am Ende erscheinen. 'char a [];' ist ** nicht ** eine "Kurzschrift für' char a [0]; '". –

Antwort

26

Sie verwenden ein Null-Bitfeld als Hacky-Methode, um Ihren Compiler dazu zu bringen, eine Struktur anzuordnen, die externen Anforderungen entspricht, sei es die Layout-Vorstellung eines anderen Compilers oder einer anderen Architektur (plattformübergreifende Datenstrukturen wie in ein binäres Dateiformat) oder Anforderungen eines Bit-Level-Standards (Netzwerkpakete oder Befehls-Opcodes).

Ein reales Beispiel ist, als NeXT den xnu Kernel von der Motorola 68000 (m68k) Architektur auf die i386 Architektur portierte. NeXT hatte eine funktionierende m68k-Version ihres Kernels. Als sie es nach i386 portierten, stellten sie fest, dass sich die Ausrichtungsanforderungen des i386 von denen der m68k so unterschieden, dass eine m68k-Maschine und eine i386-Maschine sich nicht auf das Layout der herstellerspezifischen BOOTP-Struktur von NeXT einigen konnten.Um das i386-Strukturlayout mit dem m68k übereinstimmen zu lassen, fügten sie ein unbenanntes Bitfeld der Länge Null hinzu, um die -Struktur mit 16-Bit-Ausrichtung zu erzwingen.

Hier sind die relevanten Teile aus dem Mac OS X 10.6.5 xnu Quellcode:

/* 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

Der Standard (9.6/2) nur 0 Länge Bit-Felder als Sonderfall:

Als Sonderfall, ein unbenannt Bit-Feld mit einer Breite von Null legt die Ausrichtung der nächsten Bit-Feld an einer Zuordnungseinheit Grenze. Nur wenn ein unbenanntes Bit-Feld deklariert wird, kann der Konstantenausdruck ein Wert gleich auf Null sein.

Die einzige Verwendung wird in diesem Zitat beschrieben, obwohl ich es noch nie im praktischen Code angetroffen habe.


Für das Protokoll, ich habe gerade versucht, den folgenden Code unter 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; 
} 

Die Ausgabe auf meiner Maschine ist in der Tat: 4 - 8.

+4

Ein praktisches Beispiel: http://stackoverflow.com/questions/9229601/what-is-it-in-cccode – whitequark

5

Dieses von MSDN und nicht als Microsoft Specific markiert, so dass ich denke, das gemeinsamen C++ Standard ist:

Ein ungenanntes Bit-Feld der Breite 0 Kräfte Ausrichtung des nächsten Bit-Feldes an die Grenze neben Typ, wobei Typ ist der Typ des Mitglieds.

6
struct X { int : 0; }; 

undefinierten Verhalten in C ist

See (Hervorhebung von mir):

(C99, 6.7.2.1p2) "Das Vorhandensein einer struct-declaration-list in einem struct-or-union-specifier deklariert einen neuen Typ innerhalb einer Übersetzungseinheit. Die Struktur Deklarationsliste ist eine Abfolge von Deklarationen für die Mitglieder der Struktur oder Vereinigung. Wenn die Struktur-Deklaration-Liste keine benannten Mitglieder enthält, ist das Verhalten nicht definiert "

(C11 hat den gleichen Wortlaut.)

Sie können mit einem ungenannten Bit-Feld verwenden 0 Breite aber nicht wenn es kein anderes benannte Mitglied in der Struktur

. zum Beispiel:

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

Durch die Art und Weise für die zweite Erklärung, gcc gibt eine Diagnose aus (nicht erforderlich für den C-Standard) mit -pedantic.

Auf der anderen Seite:

struct X { int :0; }; 

in GNU C definiert Es wird beispielsweise durch den Linux-Kernel (include/linux/bug.h) verwendet, um einen Übersetzungsfehler zu zwingen, den folgenden Makro zu verwenden, wenn die Bedingung erfüllt ist:

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

+1; vielleicht könnte man erwähnen, dass http://stackoverflow.com/questions/9229601/what-is-in-c-code dieses Makro genauer beschreibt. –

Verwandte Themen