web-dev-qa-db-ja.com

C不明なタイプ名 'my_structure'

私はこのコードを持っています:

main.h

#ifndef MAINH
#define MAINH
...
#include "my_struct.h"
void some_func(my_structure *x);
...
#endif

そして

my_struct.h

#ifndef UTILSH
#define UTILSH
...
#include "main.h"
...
typedef struct abcd {
    int a;
} my_structure;
...
#endif

しかし、コンパイルしようとすると次のようになります:error: unknown type name ‘my_structure’

理由は何ですか?

11
alexandernst

インクルードの順序付けのため、コンパイラは_typedef struct abcd { int a; } my_structure;_を見る前にvoid some_func(my_structure *x);を見る。

おもう。

これを見ていきましょう。

_my_struct.h_が最初に処理されると仮定すると、次の一連のイベントを取得します。

  1. UTILSHが定義されています
  2. MAINHが定義されています
  3. UTILSHはすでに定義されているため、_my_struct.h_を再度処理しないため、typedefは処理されません
  4. void some_func(my_structure *x);が処理されます。
  5. 現在 typedefが処理されます。

したがって、前処理後、コンパイラは次の宣言シーケンスを認識します。

_...
void some_func(my_structure *x);
...
typedef struct abcd {...} my_structure;
_

悪いジュジュ。 _my_structure_内の_main.h_の前方宣言が必要か、その循環依存関係を解除する必要があります(これは非常に望ましいオプションです)。 _main.h_に_my_structure.h_が実際に使用するものはありますか?その場合は、_main.h_と_my_structure.h_の両方が含まれる別個のファイルに分解する必要があります。

19
John Bode

循環ヘッダーインクルージョンを作成しました。円形の包含は決して何も達成しません。無限です。 #ifndefインクルードガードは、予測不能なポイントで無限の包含円を壊します(最初に.cファイルに含まれるヘッダーによって異なります)。これがあなたのケースで起こったことです。基本的に、循環インクルードは、最初にmain.h、2番目にmy_struct.hを含むように「解決」されました。これがmain.hmy_structタイプについて何も知らない理由です。

繰り返しますが、循環包含は何も達成しません。円形の包含を取り除きます。ヘッダー構造を階層的に設計します。低レベルヘッダーは高レベルヘッダーに含まれますが、その逆はできません。あなたの場合、my_struct.hはおそらく低レベルのヘッダーです。つまり、main.hへのmy_struct.hの挿入を停止する必要があります。 my_struct.hmain.hを必要としないように、ヘッダーを再設計します。

6
AnT

エラーメッセージは、main.hが定義されている前に、my_struct.hに含まれているときにmy_structureから送信されます。 main.hmy_struct.hが相互に含まれるため、インクルードパスを再検討する必要があります。

おそらくmain.hファイルにはmy_struct.hのみを含め、my_struct.hには何も含めないようにする必要があります。基本的に、Cコンパイラに無限の共包含ループを作成するよう指示しています。

3
yan