1. ホーム

不完全な型エラー解決へのポインタの再参照

2022-03-02 15:38:44

<スパン 今日、同僚から質問を受けたのですが、彼は、"を作るときにエラーが発生したと報告しました。 201 line: dereferencing pointer to incomplete type" で、いろいろ調べてみたのですが、原因が分かりませんでした。問題は解決し、原理も理解できたので、文書化しました。

彼の問題は具体的にはこうだった。

<テーブル
1
2
3
4
5
6
#include <netinet/ip_icmp.h>
...
struct
 icmp* aaa;
aaa = (
struct
 icmp*)
malloc
(
sizeof
(
struct
 icmp)); 
//assuming it is line 200.
aaa->icmp_type=1; 
// assuming line 201.
...

make の 201 行目でエラーが報告されました。 不完全な型へのポインタを参照しています。

まず、このエラーの意味について説明します。平たく言えば、ポインターが指す変数にアクセスしようとしたときに、その変数が不完全な型であることがわかり、構造体ユニオンのメンバにアクセスすることの方がエラーになっているということです。コードからわかるように、icmp_typeが指す変数に実際にアクセスするのは201行目からで、200行目からはまだアクセスされていない。

そこで、struct icmp が定義されていないのでは?そこで、/usr/include/netinet/ip_icmp.h ファイルをざっと見てみると、struct icmp の定義がありました。不思議でしょう?いくつかデモを書いてテストしてみた結果、最終的な結論は、確かにstruct icmpの定義はない!ということになりました。

これを見ると、さらに不思議な気持ちになります。なぜ、このような結論になるのでしょうか。もっと詳しく見てみましょう。 /usr/include/netinet/ip_icmp.h ファイルを見ると、以下のように struct icmp の定義が macroj 内に含まれていることがわかります。

<テーブル
1
2
3
4
5
6
7
8
9
...
#ifdef __USE_BSD
...
struct
 icmp {
...
}
...
#endif /*END OF ifdef __USE_BSD*/
...

ここでわかるように、gcc ... -D__USE_BSD が含まれていないコマンドでコンパイルすると、構造体 icmp の定義が含まれていないため、先ほどの 201行目でエラーになります。 そのため、定義されているのに不完全な型である理由がわからなかったのです。そこで、これを検証するためにちょっとしたデモを書いてみたところ、-D__USE_BSDをつけるとコンパイルされるが、それ以外ではコンパイルされないことがわかった。

この問題を解決する過程でかなりの数のデモを書きましたが、以下にまとめます。

<スパン 1. 不完全な型へのポインタを参照している」というエラーが発生した場合 その行の構造体変数の定義が見つかるかどうか、まず、grep "struct xxx" /usr/include -R コマンドで /usr/include ディレクトリを再帰的に検索して、見つかったら、.include に#include することができるようになります。 cファイル、非標準の場合 見つかったら.cファイルに#include、非標準のヘッダーファイルの場合、コンパイルコマンドでヘッダーファイルのディレクトリに-Iを追加、例(-I/usr/local/xxx/include)します。

2. の後もエラーが報告される場合は、#includeを使用します。 不完全な型へのポインタの再参照 "、ファイルを見て回って、構造体の定義が何らかのコンパイルマクロでラップされているかどうかを確認し、何らかのコンパイルマクロでラップされている場合は、コンパイルコマンドに-Dコンパイルマクロを追加する(例:-D__USE_BSD)。

上記の2つのステップの後、基本的に修正されるのは 不完全な型へのポインタの再参照 というエラーが発生します。