Cについては完全にはわかりませんが、C++では長さが0の名前のないビットフィールドを使用できます。例えば:
struct X
{
int : 0;
};
- 質問1:これのどのような実用的な使用法を考えることができますか?
- 質問2:実際の実際の使用法(ある場合)を知っていますか?
氷犯罪の答えの後に例を編集しました
編集: OK、現在の回答のおかげで、理論的な目的がわかりました。しかし、質問は実際の使用に関するものなので、まだ保持されています:)
Cについては完全にはわかりませんが、C++では長さが0の名前のないビットフィールドを使用できます。例えば:
struct X
{
int : 0;
};
氷犯罪の答えの後に例を編集しました
編集: OK、現在の回答のおかげで、理論的な目的がわかりました。しかし、質問は実際の使用に関するものなので、まだ保持されています:)
長さゼロのビットフィールドをハッキーな方法として使用して、コンパイラが外部要件に一致する構造をレイアウトするようにします。これは、別のコンパイラまたはアーキテクチャのレイアウトの概念(バイナリファイル形式などのクロスプラットフォームデータ構造)です。 )またはビットレベルの標準の要件(ネットワークパケットまたは命令オペコード)。
実際の例は、NeXTがxnuカーネルをMotorola 68000(m68k)アーキテクチャからi386アーキテクチャに移植した場合です。NeXTには、カーネルのm68kバージョンが機能していました。彼らがそれをi386に移植したとき、彼らは、m68kマシンとi386マシンがNeXTベンダー固有のBOOTP構造のレイアウトに同意しないという点で、i386のアライメント要件がm68kのものとは異なることに気づきました。i386構造体のレイアウトをm68kと一致させるために、長さゼロの名前のないビットフィールドを追加して、NV1
構造体/nv_U
ユニオンを16ビットに整列させました。
Mac OS X10.6.5xnuソースコードの関連部分は次のとおりです。
/* 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;
};
標準(9.6 / 2)では、特殊なケースとして長さ0のビットフィールドのみが許可されています。
特殊なケースとして、幅がゼロの名前のないビットフィールドは、アロケーションユニットの境界での次のビットフィールドの配置を指定します。名前のないビットフィールドを宣言する場合にのみ、定数式をゼロに等しい値にすることができます。
唯一の使用法はこの引用で説明されていますが、実際のコードではまだ遭遇したことがありません。
記録のために、私はVS2010で次のコードを試しました。
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
。
struct X { int : 0; };
Cでは未定義の動作です。
(強調鉱山)を参照してください:
(C99、6.7.2.1p2) "struct-or-union-specifierにstruct-declaration-listが存在すると、変換ユニット内で新しい型が宣言されます。struct-declaration-listは、構造体または共用体のメンバー。struct-declaration-listに名前付きメンバーが含まれていない場合、動作は未定義です"
(C11の文言は同じです。)
幅のある名前のないビットフィールドを使用できますが0
、構造体に他の名前の付いたメンバーがない場合は使用できません。
例えば:
struct W { int a:1; int :0; }; // OK
struct X { int :0; }; // Undefined Behavior
ちなみに、2番目の宣言ではgcc
、で診断(C標準では必要ありません)を発行し-pedantic
ます。
一方で:
struct X { int :0; };
はGNUCで定義されています。これは、たとえばLinuxカーネル(include/linux/bug.h
)によって使用され、条件がtrueの場合に次のマクロを使用してコンパイルエラーを強制します。
#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); }))
これはMSDNからのものであり、Microsoft固有としてマークされていないため、これは一般的なC++標準であると思います。
幅0の名前のないビットフィールドは、次のビットフィールドを次のタイプ境界に強制的に整列させます。ここで、typeはメンバーのタイプです。
C11標準では、長さゼロのビットフィールドを含めることができるようになりました。これはC委員会ドラフト(N1570)の例であり、実際の使用法を示していると思います。
3.14メモリ位置
...
4。例として宣言された構造体struct { char a; int b:5, c:11, :0, d:8; struct { int ee:8; } e; }
4つの個別のメモリ位置が含まれています。メンバーと
a
ビットフィールドはそれぞれ個別のメモリ位置であり、互いに干渉することなく同時に変更できます。ビットフィールドと一緒に4番目のメモリ位置を構成します。ビットフィールドとを同時に変更することはできませんが、たとえば、とは変更できます。d
e.ee
b
c
b
c
b
a
したがって、ビットフィールドの間に長さゼロのビットフィールドを含めるc
と、とd
の同時変更も可能になりb
ますd
。