6.21 デバッグの手法
6.21.2 警告メッセージ
C言語の警告メッセージは,バグの原因を指摘していることが多い. そのため,警告メッセージを減らす ことはバグを取り除くために有用な方法である. gccにおいて,全ての警告を出力するには,コンパイル時 に-Wall オプションをつける.
頻繁にお目にかかる警告メッセージには,以下のようなものがある.
1. 関数宣言に関わるメッセージ. (重大度:中)
gccでは“implicit declaration of function”と表示される.
戻り値がintである関数の場合には問題が生じないが,そうでない関数の場合にはエラーとなる潜在 的危険性がある.
gccでは“implicit declaration of function”と表示されるエラーとなる場合もある. この場合には,
• “type mismatch with previous implicit declartion”
• “previouly implicitly declaration”
などという警告と同時に発生する.
2. 未使用の変数の存在. (重大度:小)
gccでは“unused variable”と表示される.
未使用の変数はメモリエリアを圧迫する可能性がある. また,プログラムコードが醜くなる.
3. 関数引数の型の不一致. (重大度:大)
gccでは“incompatible type for argument”と表示される. また, “different type arg”と表示される こともある.
4. ポインタの型の不一致. (重大度:大)
gccでは“assignment makes pointer from *** without a cast”と表示される.
Example 6.21.6 “implicit declaration of function” の例.
int main(int argc, char **argv) {
printf("\n") ; return 0 ; }
test.c: In function ‘main’:
test.c:3: warning: implicit declaration of function ‘printf’
#include <stdio.h> がないため, printf 関数の前方宣言がない. そのため, 関数宣言に矛盾が生じて いる.
Example 6.21.7 “implicit declaration of function” でエラーとなる例.
#include <stdio.h>
int main(int argc, char **argv) {
int i ; a() ; return 0 ; }
void a() {
return ; }
test.c: In function ‘main’:
test.c:5: warning: implicit declaration of function ‘a’
test.c:4: warning:
unused variable ‘i’
test.c: At top level:
test.c:10: warning: type mismatch with previous implicit declaration test.c:5: warning: previous implicit
declaration of ‘a’
test.c:10: warning: ‘a’ was previously
implicitly declared to return ‘int’
関数aには前方宣言が存在していない. そのため,一旦はintと理解してコンパイルされるが,その後void と宣言されるため矛盾が生じる.
Example 6.21.8 “incompatible type for argument” の例.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv) {
double x,y;
x = atoi(y) ; return 0 ; }
test.c: In function ‘main’:
test.c:6: incompatible type for argument 1 of ‘atoi’
atoi関数は,引数はchar *である.
Example 6.21.9 “different type”の例.
#include <stdio.h>
int main(int argc, char **argv) {
int i,j ;
printf("%d, %f\n", i,j) ; return 0 ;
}
test.c: In function ‘main’:
test.c:5: warning: double format, different type arg (arg 3)
printf関数の第3引数と,第2引数の%表示が対応していない.
Example 6.21.10 ポインタの型の不一致の例.
#include <stdio.h>
int main(int argc, char **argv) {
int i, *p ; p = i ; return 0 ; }
test.c: In function ‘main’:
test.c:5: warning: assignment makes
pointer from integer without a cast
「5行目」のポインタ代入は明らかな間違いである. もし,int *pのかわりにint p[10]とするとエラー となるが,ポインタ形式の場合にはエラーではなく, 警告となることに注意.
ポインタ代入に関しては,型が異ると常にこの警告が出てくる.
Example 6.21.11 -ansi -pedanticオプションをつけずにコンパイルしたときには問題がないが,-ansi
-pedanticオプションをつけるとコンパイルできない例.
#include <stdio.h>
int main(int argc, char **argv) {
int n, a[n] ; return 0 ; }
test.c: In function ‘main’:
test.c:5: warning: ANSI C forbids variable-size array ‘a’
ANSI Cでは可変サイズの配列は認められていない. C++では可変サイズの配列が認められているため,
-ansi -pedanticをはずすと警告が出てこない.
6.21.2.1 リンクエラー
リンク時のエラーは,コンパイルしたコードとライブラリを結合する際に,全てのシンボル名(名前)を 解決出来ないことが原因となる.
Example 6.21.12
#include <stdio.h>
#include <math.h>
int main(int argc, char **argv) {
printf("%f\n", sqrt(2.0)) ; return 0 ;
} を gcc test.c
としてコンパイルすると,
Undefined first referenced
symbol in file
sqrt /var/tmp/ccx1zyDC.o
ld: fatal: Symbol referencing errors. No output written to a.out collect2: ld returned 1 exit status
というリンクエラーが発生する.
この例では, 数学関数sqrt というシンボルが解決できていない. 数学関数を利用する場合には, リンク 時に-lmというオプションを最後につけなければならない.
gcc test.c -lm
とすればエラーは解決できる.
Example 6.21.13
/* test0.c */
#include <stdio.h>
int a=1 ;
int main(int argc, char **argv) {
a = 2 ; return 0 ; }
/* test1.c */
#include <stdio.h>
int a=1 ;
int main(int argc, char **argv) {
a = 2 ; return 0 ; }
を
gcc -c test0.c gcc -c test1.c
gcc test0.o test1.o -o a.out としてコンパイルすると,
ld: fatal: symbol ‘a’ is multiply defined:
(file test.o and file test1.o);
ld: fatal: symbol ‘main’ is multiply defined:
(file test.o and file test1.o);
ld: fatal: File processing errors. No output writt というリンクエラーが発生する.
この例は2つエラーがあり,
• main 関数が2つのコードにあり,エントリポイントを決定できない.
• 静的変数 aがともに初期化されているため,両方の変数aのリンケージが決定できない.
第2の問題を解決するには,どちらかで初期化をやめることになる.