27

次の例は、Cの有効な完全な翻訳単位ですか?

struct foo;

struct foo *bar(struct foo *j)
{
    return &*j;
}

struct fooは不完全な型ですが、C標準で不完全な型を間接参照することの明示的な禁止を見つけることができません。特に、§6.5.3.2は次のように述べています。

単項&演算子は、そのオペランドのアドレスを生成します。オペランドの型が「type」の場合、結果の型は「pointertotype」になります。オペランドが単項演算子の結果である場合、*その演算子も演算子も&評価されず、演算子の制約が引き続き適用され、結果が左辺値ではないことを除いて、結果は両方が省略されたかのようになります。

結果が左辺値ではないという事実は密接な関係はありません-戻り値はそうである必要はありません。*演算子の制約は単純です。

単項*演算子のオペランドは、ポインター型でなければなりません。

および&演算子は次のとおりです。

単項演算子のオペランドは&、関数指定子、単項演算子[]または単項演算子の結果、または*ビットフィールドではなくregisterストレージクラス指定子で宣言されていないオブジェクトを指定する左辺値のいずれかでなければなりません。

ここでは両方とも簡単に満たされるので、結果はちょうど。と同等になるはずですreturn j;

ただし、gcc4.4.5はこのコードをコンパイルしません。代わりに、次のエラーが発生します。

y.c:5: error: dereferencing pointer to incomplete type

これはgccの欠陥ですか?

4

3 に答える 3

7

はい、バグだと思います。不完全な型の左辺値でも*j、コンテキストによっては許可されるようです:

6.3.2.1 ...左辺値はオブジェクト型または void 以外の不完全な型を持つ式です

基本的に、これは、の構造について知る必要があるような左辺値で何もしない限り、機能するはずですstruct。したがって、オブジェクトにアクセスしたり、そのサイズについて質問したりしない場合、これは合法です。

于 2011-08-04T08:32:51.197 に答える
3

C99 標準 (ISO/IEC 9899:1999) では、動作について次のように説明されています。

§6.5.3.2 アドレスおよび間接演算子

単項 & 演算子は、そのオペランドのアドレスを返します。オペランドの型が ''type'' の場合、結果の型は ''pointer to type'' になります。オペランドが単項 * 演算子の結果である場合、その演算子も & 演算子も評価されず、演算子に対する制約が引き続き適用され、結果が左辺値ではないことを除いて、結果は両方が省略されたかのようになります。

これは&*jと同等であることを意味しjます。

ただし、jオブジェクトへのポインターであると想定されており、GCC 4.4.5 が言うように、不完全な型へのポインターにすぎません。

§6.3.2.3 ポインタ

void へのポインターは、任意の不完全型またはオブジェクト型へのポインターとの間で変換できます。不完全型またはオブジェクト型へのポインターは、void へのポインターに変換され、再び元に戻される可能性があります。結果は元のポインターと等しくなります。

オブジェクト型と不完全型を区別することに注意してください。これは標準で頻繁に発生します。

したがって、質問のこの観察は正しくありません。

どちらもここで自明に満たされていますが、

変数jはオブジェクトへのポインターではありません。オブジェクトではない不完全な型へのポインタです。


§6.2.5 タイプ

[...] 型は、オブジェクト型 (オブジェクトを完全に説明する型)、関数型 (関数を説明する型)、および不完全型 (オブジェクトを説明するが、サイズを決定するために必要な情報が不足している型) に分割されます。

于 2011-08-04T09:24:30.047 に答える
2

はい。Cのポインターは通常、同じサイズです(一部の組み込みシステムでは、異なる場合があります)。これは、型が「不明」であっても、コンパイラがこのための正しいアセンブラコードを生成できることを意味します。

このアプローチを使用して、内部データ構造を外部に完全に隠すことができます。を使用しtypedefて構造体へのポインターを宣言し、内部ヘッダーファイル(つまり、パブリックAPIの一部ではないファイル)でのみ構造体を宣言します。

gcc 4.4.5が文句を言う理由は、次のとおりです。実装の外部で不完全な型へのポインターを使用する場合、それは機能するはずです。ただし、コードは実装の一部であり、ここでは、完全な型が必要になる可能性があります。

于 2011-08-04T07:56:32.247 に答える