1. ホーム
  2. c++

[解決済み] この構造体はどうしてsizeof==0になるのですか?

2023-06-26 20:30:25

質問

古い記事で sizeof が返す 0 . 高評価のユーザーから、標準では型や変数がsizeof 0を持つことはできないという回答がありましたが、私もそれに100%同意します。

しかし、そこには この新しい回答 があり、この解決策を提示しています。

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

私はちょうどダウンボーティングしてコメントするところでしたが、ここで過ごした時間は、私が100%確信していることでさえ確認することを教わりました。それで...驚いたことに、両方とも gccclang は同じ結果を示す。 sizeof(ZeroMemory) == 0 . さらに言えば、変数のsizeofは 0 :

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

な、なんだ......?

ゴッドボルトのリンク

どうしてこんなことが可能なのでしょうか?

どのように解決するのですか?

C 言語が標準化される以前は、コードが別のものからゼロ サイズの型へのポインタを決して引こうとしない限り、多くのコンパイラーはゼロ サイズの型の処理に何の問題もありませんでした。 そのような型は有用であり、それをサポートすることはそれを禁止するよりも簡単で安上がりだったのです。 しかし、他のコンパイラはそのような型を禁止することに決め、コードがゼロサイズの配列を作成しようとすると、静的アサーティションコードはその事実に依存していたかもしれません。 標準の作成者は選択に迫られました。

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

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

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

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

C++ 標準規格では、空のオブジェクトの存在を認めていますが、空のオブジェクトのアドレスをトークンとして使用できるようにするために、最小のサイズが 1 であることを義務付けています。 しかし、オブジェクトにサイズ0のメンバが含まれている場合、C++標準は、そのような宣言を含むプログラムが診断を開始しなければならないという事実以外に、その宣言の処理方法について何の要件も課していません。 このような宣言を使用するほとんどのコードは、結果として生じるオブジェクトのサイズが 0 であることを想定しているため、このようなコードを受け取るコンパイラにとって最も有益な動作は、このように扱うことです。