3.6.1 はじめに
デフォルトの場合、コンパイラとアセンブラは、高レベルの型情報を生成します。(-g0で)型情報の生成を オフにしていない限り、それぞれのオブジェクトには、高レベルの型情報が含まれることになります。リ ンカは、この型情報を比較し、矛盾があればそれについて警告を出します。リンカは、次の4種類の型矛盾 を区別します。
1. 型が正しく指定されていない場合(W109)。配列の深さを指定していない場合、または関数プロトタイ プで引数を指定していない場合に発生します。警告レベル9を指定していない限り(-w9)、リンカはこの 種の矛盾を報告しません。デフォルトの警告レベルは8です。
2. 型に互換性があるにもかかわらず、定義が異なる場合(W110)。たとえばshort型にint型をリンクした場 合に発生します。S1C88は、どちらも16ビットと見なすため、問題にはなりません。しかし、このよう なコードには移植性がなくなります。また、異なる名前の構造体や型を使用しても、この警告が発生し ます。このメッセージの警告レベルは8であるため、この種のメッセージをオフにするためには、警告 レベルを7以下に設定します(-w7)。
3. 符号付き/符号なしの矛盾(W111)。signed intをunsigned intとリンクすると、このメッセージが出されま す。多くの場合問題はありませんが、符号なしバージョンでは、整数値が大きくなります。このメッ セージの警告レベルは6であるため、この種のメッセージを抑制するためには、警告レベルを5以下に設 定します(-w5)。
4. その他の矛盾(W112)。警告112が出された場合、もっと重大な型矛盾があると考えられます。関数の戻 り型の矛盾、2つの組み込み型の長さの矛盾(short/long)、型が完全に異なる場合などが考えられます。
このメッセージの警告レベルは4であるため、この種のメッセージをオフにするためには、警告レベル を3以下に設定します(-w3)。
3.6.2 再帰的な型チェック
リンカは、型を再帰的に比較します。たとえば、fooの型の場合を考えます。
struct s1 {
struct s2 *s2_ptr;
};
struct s2 { int count;
} sample;
struct s1 foo = { &sample };
このソースをコンパイルして、次のような、struct s2が異なるだけの他のコンパイル済みソースとリン クした場合、
struct s1 {
struct s2 *s2_ptr;
};
struct s2 { short count;
};
extern struct s1 foo;
メッセージW112(型の矛盾)が生成されます。struct s1はどちらの場合も同じですが、実数型の矛盾に なります。たとえばコード"foo.s2_ptr->count++"の場合、両方のオブジェクトで異なるコードが生成 されます。
1つのシンボルに複数の矛盾がある場合、リンカは低い方の警告レベルの矛盾(もっとも重大なもの)を報告 します。
3.6.3 関数間の型チェック
K&Rスタイルの関数を使用する場合、引数の型および引数の数値をチェックすることはできません。特に 指定されていない場合、戻り型は"int"になります。プロトタイプは、関数の戻り型が整数型以外の場合のみ 必要になります。
test2( par ) int par;
{
test1( par );
return test3( 1, 2 );
}
この場合、test1(他のソースで定義されたもの)の戻り型はvoidで、test3の戻り型はデフォルトのint になっています。デフォルトの警告レベルの場合、リンカは矛盾を報告しません。警告レベル9を指定した 場合(-w9)、リンカが引数をチェックしないため、リンカは"型が正しく指定されていない場合"を報告しま す。戻り型の矛盾は、警告レベル4の実数型の矛盾になります。
ソースがANSIスタイルの場合(推奨)、リンカは、すべてのパラメータの型およびパラメータの数値をチェッ クします。この場合、上記の例のソースは次のようになります。
void test1( int ); /* ANSI style prototypes */
int test3( int, int );
test2( int par ) /* ANSI style function definition*/
{
test1( par );
return test3( 1, 2 );
}
test1およびtest3の定義を含むソースは、次のようになっています。
void test1( int one ) {
/*
** code for function test1
*/
. . . }
int test3( int one, int two ) {
/*
** Code for function test3
*/
. . . }
プロトタイプは、ある関数がソース内で定義される前に参照される場合のみ必要になります。しかし、1つ のファイルですべての関数についてプロトタイプを記述しておき、そのプロトタイプファイルをインクルー ドすることもできます。こうすると、関数の型チェックがコンパイラによって行われるようになります。
それにもかかわらず、プロトタイプファイルを変更した後すべてのソースをコンパイルしなかった場合、
リンカによって型の矛盾が報告されます。
ANSIスタイルのプロトタイプをK&RスタイルのCコードに追加することができます。この場合、関数につ いて完全な型チェックが可能になります。これを実行するためには、作成するアプリケーションで、すべ ての関数についてのすべてのプロトタイプを記述した新しいヘッダファイルを作成します。このファイル をそれぞれのソースにインクルードするか、-Hオプションを指定することにより、コンパイラに対してこ のファイルをインクルードするよう命令します。
cc88 -c -Hproto.h *.c
3.6.4 指定されていない型
Cでは、指定されていないオブジェクトに対するポインタを定義することができます。リンカは、このよう な型をチェックすることができません。例を示します。
struct s1 {
struct s2 *s2_ptr;
};
struct s1 foo;
構造体s2は指定されていません。リンカは、struct s2がすべてのソースで同じかどうかチェックするこ とができないため、次のようなレベル9の警告が出されます。
lk88 W102(9) <name>: Incomplete type specification, type index = T101
struct s2が他のソースで認識されている可能性もあります。このソースが変数fooを使用する場合、レ ベル9の型の矛盾を報告する2番目のメッセージが生成されます。
lk88 W109(9) <fl>: Type not completely specified for symbol <foo> in <f2>
最初の警告は、型の定義が完全でないため、リンカが型をチェックできないことを報告しています。ただ し、これはCで認められています。このメッセージは、不完全な型があれば、オブジェクトごとに一度ずつ 出されます。2番目のメッセージは、不完全な型と完全な型とで、型が異なることを報告しています。これ らのすべての警告は、警告レベル9を指定した場合(-w9)にのみ生成されます。