Oracle Solaris Studio 12.2: C ユーザーガイド

6.11 不完全な型

C の当初から内在し、C の基本的な部分であるがまだ真価を認められていない部分を正式なものとするために、ISO C 規格は「不完全な型」を導入しました。この節では、不完全な型がどこで許可されるかと、なぜ便利であるかを説明します。

6.11.1 型

ISO は C の型を、関数、オブジェクト、および不完全の 3 つに区分しました。関数型の定義は明白です。オブジェクト型は、サイズが不明なオブジェクトを除く、そのほかすべてのものを示します。ANSI/ISO C 規格は、明示されるオブジェクトのサイズが既知でなければならないことを指定するために、「オブジェクト型」を使用します。しかし、void 以外の不完全な型もオブジェクトを指すことは十分に理解してください。

不完全な型には、void、不特定長の配列、および不特定内容の構造体と共用体の 3 つの種類しかありません。型 void は、完成させることができない不完全な型であるという点でほかの 2 つとは異なります。そして、特別な関数の戻り型とパラメータ型として機能します。

6.11.2 不完全な型を完全にする

不完全な配列型を完全なものにするには、同じオブジェクトを示す同じスコープ内にある後続の宣言で、配列のサイズを指定します。同じ宣言でサイズが不明な配列 (不特定長の配列) が宣言および初期化されるとき、その配列は、宣言の終わりから初期化の終わりまでの間だけ、不完全な型になります。

不完全な構造体型または共用体型を完成させるには、同じタグの同じスコープ内にある後続の宣言で、構造体型または共用体型の内容を指定します。

6.11.3 宣言

不完全な型を使用できる宣言もありますが、完全なオブジェクト型が必要な宣言もあります。オブジェクト型を必要とする宣言は、配列要素、構造体または共用体のメンバー、および関数に局所的なオブジェクトです。ほかのすべての宣言は、不完全な型を許可します。特に、次の構造が許可されています。

関数の戻り型とパラメータ型は特別です。このような方法で使用される不完全な型 (void を除く) は、関数が宣言または呼び出されるときまでに完全にならなければいけません。void の戻り型は、値を返さない関数を指定します。また、void の単一のパラメータ型は、引数を受け入れない関数を指定します。

配列と関数のパラメータ型はポインタ型に書き換えられるため、配列のパラメータ型は外見上不完全ですが、実際には不完全ではありません。典型的な mainargv (つまり、char *argv[]) の宣言は、不特定長の文字ポインタの配列として、文字ポインタへのポインタとして書き換えられます。

6.11.4 式

ほとんどの式演算子では完全なオブジェクト型が必要ですが、例外が 3 つあります。単項 & 演算子、コンマ演算子の最初のオペランド、および ?: 演算子の 2 番目と 3 番目のオペランドです。ポインタのオペランドを受け入れるほとんどの演算子は、ポインタ演算が要求されないかぎり、不完全な型へのポインタも許可します。この中には、単項 * 演算子も含まれます。たとえば、次の例を見てください。


void *p

&*p は、この例を使用する有効な式の一部です。

6.11.5 正当性

なぜ不完全な型が必要なのでしょうか。void を除いて、C ではほかの方法で扱えない不完全な型の唯一の機能は、構造体と共用体の前方参照です。たとえば、2 つの構造体がお互いを指すポインタを必要とする場合、これを実現するためには、不完全な型を使用しなければいけません。


struct a { struct b *bp; };
struct b { struct a *ap; };

異なる形式のポインタや異なる種類のデータ型を持つ、強力な型依存プログラミング言語には、すべて前述のようなケースを処理するための方法が用意されています。

6.11.6 例

不完全な構造体型や共用体型には typedef 名の定義が役立ちます。データ構造が複雑な (お互いへのポインタを多数持つような) 場合は、構造体への typedef のリストを前方に (中心となるヘッダーに) 指定することによって、宣言が簡単になります。


typedef struct item_tag Item;
typedef union note_tag Note;
typedef struct list_tag List;
.  .  .
struct item_tag { .  .  .  };
.  .  .
struct list_tag {
    struct list_tag {
};

さらに、内容がプログラムの残りで使用できてはいけない構造体や共用体に対しては、内容なしのタグをヘッダーに宣言できます。プログラムのほかの部分は、何の問題もなく不完全な構造体や共用体へのポインタを使用できます。ただし、そのメンバーは使用できません。

不特定長の外部配列は不完全な型として頻繁に使用されます。一般的に、配列の内容を使用するために、配列の大きさを知る必要はありません。