Sizeof演算子がCまたはC++で0(ゼロ)を返すことは可能ですか?可能であれば、標準の観点から正しいですか?
C++では、空のクラスまたは構造体には、定義上、少なくとも1つのsizeof
があります。 C++標準から、9/3「クラス」:「クラスタイプの完全なオブジェクトとメンバーサブオブジェクトのサイズはゼロ以外でなければなりません。」
Cでは、拡張機能(またはコンパイラーの欠陥)を除いて、空の構造体は許可されていません。
これは、6.7.2.1/7「構造体と共用体の指定子」からのこの文と一緒に文法(中括弧内に何かが必要)の結果です:「struct-declaration-listに名前付きメンバーが含まれていない場合、動作未定義です」。
ゼロサイズの構造が許可されている場合、それは言語拡張(またはコンパイラーの欠陥)です。たとえば、GCCでは、拡張機能は "Structures with No Members" に記載されています。
GCCでは、C構造体にメンバーを含めることはできません。
struct empty { };
構造のサイズはゼロになります。 C++では、空の構造体は言語の一部です。 G ++は、空の構造体を
char
型の単一のメンバーがあるかのように扱います。
sizeof
は、CおよびC++では0
を返しません。 sizeof
が0
に評価されるのを見るたびに、それは言語とは何の関係もない特定のコンパイラのバグ/グリッチ/拡張です。
Cのすべてのオブジェクトには、一意のアドレスが必要です。別の言い方をすれば、アドレスは、指定されたタイプのオブジェクトを1つだけ保持する必要があります(ポインターの逆参照が機能するため)。そうは言っても、「空の」構造体を考えてみましょう。
_struct emptyStruct {};
_
そして、より具体的には、それらの配列:
_struct emptyStruct array[10];
struct emptyStruct* ptr = &array[0];
_
オブジェクトが実際に空の場合(つまり、sizeof(struct emptyStruct) == 0
の場合)、ptr++ ==> (void*)ptr + sizeof(struct emptyStruct) ==> ptr
ですが、これは意味がありません。 _*ptr
_は、_ptr[0]
_または_ptr[1]
_のどちらのオブジェクトを参照しますか?
構造体に内容がない場合でも、コンパイラーは、「1つのアドレス、1つのオブジェクト」の原則を維持するために、構造体を1バイトの長さであるかのように扱う必要があります。
C言語仕様(セクションA7.4.8)は、この要件を次のように表現しています。
構造体または共用体に適用すると、(
sizeof
演算子の)結果は、オブジェクトのタイルを配列にするために必要なパディングを含む、オブジェクトのバイト数になります。
配列で機能するには、パディングバイトを「空の」オブジェクトに追加する必要があるため、sizeof()
は、有効な入力に対して少なくとも1の値を返す必要があります。
編集: C仕様のセクションA8.3は、メンバーのリストのない構造体を不完全な型と呼び、sizeof
の定義は具体的に(強調を追加):
演算子(sizeof)オペランドに適用できない関数型、不完全型、またはビットフィールド。
これは、空の構造体でsizeof
を使用することは、定義されていないデータ型で使用することと同じくらい無効であることを意味します。コンパイラが空の構造体の使用を許可している場合、C仕様により、それらにsizeof
を使用することは許可されていないことに注意してください。コンパイラでこれを実行できる場合は、これが非標準の動作であり、すべてのコンパイラで機能するとは限らないことを理解してください。この動作に依存しないでください。
編集: Bjarne StroustrupのFAQの このエントリ も参照してください。
typedef struct {
int : 0;
} x;
x x1;
x x2;
MSVC 2010(/ Za/Wall)の場合:
sizeof(x) == 4
&x1 != &x2
GCC(-ansi -pedantic -Wall)の下で:
sizeof(x) == 0
&x1 != &x2
つまり、GCCではサイズがゼロですが、構造体のインスタンスには個別のアドレスがあります。
ANSI C(C89およびC99-私はC++を見ていません)は、「オブジェクトの個々のバイトのアドレスを一意に表現できるはずです」と述べています。サイズがゼロのオブジェクトの場合、おそらくバイトがないため、これはあいまいに見えます。
編集:「宣言子がなく、コロンと幅のみのビットフィールド宣言は、名前のないビットフィールドを示します。この特殊なケースとして、幅が0のビットフィールドは、それ以上ビットフィールドがないことを示します。前のビットフィールドが配置されていたユニットにパックされます。」
私の見解では、sizeofはサイズ0の構造体に対して0を返す方が良いです(cの精神で)。しかし、プログラマーは空の構造体のサイズを取るときに注意する必要があります。
ただし、問題が発生する可能性があります。そのような構造の配列が定義されると、
&arr [1] ==&arr [2] ==&arr [0]
それは彼らに彼らのアイデンティティを失わせます。
それが可能かどうかにかかわらず、これはあなたの質問に直接答えるものではないと思います。コンパイラによっては可能かもしれません。 (上記のマイケルの答えで述べたように)。
私はそれがcで0を返すことは決してないと思います、空の構造体は許可されていません
あなたがこれを持っているなら:
struct Foo {};
struct Bar { Foo v[]; }
g++ -ansi
はsizeof(Bar)== 0を返します。clang&intelコンパイラも同様です。
ただし、これはgccではコンパイルされません。私はそれがC++拡張であると推測します。
これがテストで、sizeofは0を生成します
#include <stdio.h>
void func(int i)
{
int vla[i];
printf ("%u\n",(unsigned)sizeof vla);
}
int main(void)
{
func(0);
return 0;
}