web-dev-qa-db-ja.com

この構造はどのようにsizeof == 0を持つことができますか?

sizeof0を返すコンストラクトを要求する古い投稿があります。評判の高いユーザーからは、標準では型や変数のサイズを0にすることはできないという高得点の回答がいくつかあります。そして、それに100%同意します。

ただし、このソリューションを示す この新しい回答 があります。

struct ZeroMemory {
    int *a[0];
};

私はちょうど投票してそれについてコメントしようとしていましたが、ここで過ごした時間は、私が100%確信していることさえチェックするように教えてくれました。驚いたことに、gccclangの両方が同じ結果を示しています:sizeof(ZeroMemory) == 0。さらに、変数のサイズは0です:

ZeroMemory z{};
static_assert(sizeof(z) == 0); // Awkward...

うわぁ...?

ゴッドボルトリンク

これはどのように可能ですか?

78
bolov

Cが標準化される前は、コードがゼロサイズタイプへのポインターを別のポインターから減算しようとしない限り、多くのコンパイラーはゼロサイズタイプを処理するのに困難はありませんでした。そのような型は有用であり、それらをサポートすることは、それらを禁止するよりも簡単で安価です。ただし、他のコンパイラはそのような型を禁止することを決定し、一部の静的アサーションコードは、コードがサイズ0の配列を作成しようとした場合にスカウクするという事実に依存していた可能性があります。標準の作成者は、選択に直面しました。

  1. コンパイラが診断をトリガーしてコンパイルを中止することを目的とする場合でも、コンパイラがゼロサイズの配列宣言を黙って受け入れることを許可し、すべてのコンパイラがゼロサイズのオブジェクトを生成するとして(必ずしも黙ってではなく)そのような宣言を受け入れることを要求する。

  2. そのような宣言の目的が診断をトリガーしてコンパイルを中止することである場合でも、コンパイラがゼロサイズの配列宣言を静かに受け入れることを許可し、そのような宣言に遭遇したコンパイラがコンパイルを中止するか、自由にそれを続行できるようにします。

  3. コードがゼロサイズの配列を宣言する場合、実装が診断を発行することを要求しますが、実装は、自由にコンパイルを中止するか、適切なセマンティクスでそれを続行できます。

標準の作成者は#3を選択しました。その結果、サイズがゼロの配列宣言は、標準が禁止する前にそのような構成体が広くサポートされていたとしても、標準の「拡張」によって考慮されます。

C++標準では、空のオブジェクトの存在が許可されていますが、空のオブジェクトのアドレスをトークンとして使用できるようにするために、最小サイズは1にすることが義務付けられています。したがって、0は標準に違反します。ただし、オブジェクトにサイズがゼロのメンバーが含まれる場合、C++標準では、そのような宣言を含むプログラムが診断をトリガーする必要があるという事実を超えて、オブジェクトの処理方法に関する要件はありません。そのような宣言を使用するほとんどのコードは、結果のオブジェクトのサイズがゼロであることを期待しているため、そのようなコードを受け取るコンパイラーにとって最も有用な動作は、そのように扱うことです。

50
supercat

Jarod42 によって指摘されているように、ゼロサイズの配列は標準C++ではなく、GCCおよびClang拡張です。

-pedanticを追加すると、次の警告が生成されます。

5 : <source>:5:12: warning: zero size arrays are an extension [-Wzero-length-array]
    int *a[0];
           ^

std=c++XXの代わりにstd=gnu++XXがすべての拡張機能を無効にするわけではないことを常に忘れています。

これはまだsizeofの動作を説明していません。しかし、少なくとも標準ではないことはわかっています...

40
bolov

C++では、サイズがゼロの配列は不正です。

ISO/IEC 14882:2003 8.3.4/1:

[..]constant-expression(5.19)が存在する場合、整数定数式であり、その値は大きくなるゼロよりも。定数式は、配列の境界(要素の数)を指定します。定数式の値がNの場合、配列はNから0N-1までの番号が付けられ、Dの識別子のタイプは“ 派生宣言子タイプリストN T”の配列。 [..]

g ++では、サイズがゼロの配列に警告を出すために-pedanticフラグが必要です。

18
msc

長さゼロの配列は、GCCおよびClangによる拡張です。 sizeofを長さゼロの配列に適用 ゼロに評価

C++クラス(空)のサイズは0にできませんが、ZeroMemoryクラスは空ではないことに注意してください。サイズが0の名前付きメンバーがあり、sizeofを適用するとゼロが返されます。

4
haccks