130

構造体を含む source.c ファイルがある場合:

struct a { 
    int i;
    struct b {
        int j;
    }
};

この構造体を別のファイル (つまり ) でどのように使用できますfunc.cか?

新しいヘッダー ファイルを作成し、そこで構造体を宣言して、そのヘッダーを に含める必要がありますfunc.cか?

または、構造体全体をヘッダー ファイルで定義し、それを と の両方に含める必要がsource.cありfunc.cますか? extern両方のファイルで構造体を宣言するにはどうすればよいですか?

私はtypedefそれをすべきですか?もしそうなら、どのように?

4

3 に答える 3

153

この構造が他のファイル func.c で使用される場合、どうすればよいですか?

型がファイル (つまり func.c ファイル) で使用される場合、それは可視でなければなりません。これを行う最悪の方法は、必要な各ソース ファイルにコピー ペーストすることです。

正しい方法は、ヘッダー ファイルに配置し、必要に応じてこのヘッダー ファイルをインクルードすることです。

新しいヘッダー ファイルを開いて、そこで構造を宣言し、そのヘッダーを func.c に含めますか?

これは、コードを高度にモジュール化するため、私がより気に入っているソリューションです。私はあなたの構造体を次のようにコーディングします:

#ifndef SOME_HEADER_GUARD_WITH_UNIQUE_NAME
#define SOME_HEADER_GUARD_WITH_UNIQUE_NAME

struct a
{ 
    int i;
    struct b
    {
        int j;
    }
};

#endif

この構造を使用する関数を同じヘッダーに配置します (「意味的に」その「インターフェイス」の一部である関数)。

そして通常、構造名にちなんでファイルに名前を付け、その名前を再度使用してヘッダー ガードの定義を選択することができます。

構造体へのポインターを使用して関数を宣言する必要がある場合、完全な構造体定義は必要ありません。次のような単純な前方宣言:

struct a ;

十分であり、カップリングが減少します。

または、ヘッダー ファイルで全体の構造を定義し、それを source.c と func.c の両方に含めることはできますか?

これは別の方法で、いくらか簡単ですが、モジュール性は低くなります。機能するために構造のみを必要とする一部のコードには、すべての型を含める必要があります。

C++ では、これは興味深い複雑さにつながる可能性がありますが、これはトピック外 (C++ タグなし) であるため、詳しく説明しません。

次に、その構造を両方のファイルで extern として宣言する方法。?

おそらく要点がわかりませんが、Greg Hewgill は彼の投稿How to declare a structure in a header that is to be used by multiple files in c? で非常に良い答えを持っています。.

それをtypedefしましょうか?

  • C++ を使用している場合は、使用しないでください。
  • C を使用している場合は、そうする必要があります。

その理由は、C 構造体の管理が苦痛になる可能性があるためです。構造体キーワードを使用するすべての場所で宣言する必要があります。

struct MyStruct ; /* Forward declaration */

struct MyStruct
{
   /* etc. */
} ;

void doSomething(struct MyStruct * p) /* parameter */
{
   struct MyStruct a ; /* variable */
   /* etc */
}

typedef を使用すると、struct キーワードなしで記述できます。

struct MyStructTag ; /* Forward declaration */

typedef struct MyStructTag
{
   /* etc. */
} MyStruct ;

void doSomething(MyStruct * p) /* parameter */
{
   MyStruct a ; /* variable */
   /* etc */
}

構造体の名前を保持しておくことが重要です。書き込み:

typedef struct
{
   /* etc. */
} MyStruct ;

typedef された名前を持つ匿名構造体を作成するだけで、それを前方宣言することはできません。したがって、次の形式を守ってください。

typedef struct MyStructTag
{
   /* etc. */
} MyStruct ;

したがって、struct キーワードの追加を避けたい場所ならどこでも MyStruct を使用でき、typedef が機能しない場合 (つまり、前方宣言) には MyStructTag を使用できます。

編集:

Jonathan Lefflerが正しく指摘したように、C99 構造体宣言に関する誤った仮定を修正しました。

2018-06-01 を編集:

Craig Barnesはコメントで、構造体の "タグ" 名とその "typedef" 名に別々の名前を付ける必要がないことを思い出させてくれます。

実際、上記のコードは次のように書くこともできます。

typedef struct MyStruct
{
   /* etc. */
} MyStruct ;

IIRC、これは実際には、C との互換性を維持するために、C++ が舞台裏で単純な構造体宣言を使用して行うことです。

// C++ explicit declaration by the user
struct MyStruct
{
   /* etc. */
} ;
// C++ standard then implicitly adds the following line
typedef MyStruct MyStruct;

C に戻ると、両方の使用法 (別の名前と同じ名前) を見てきましたが、私が知っている欠点はありません。したがって、構造体やその他のシンボルに C の別の「名前空間」を使用しない場合、同じ名前を使用すると読みやすくなります。 .

于 2008-10-23T06:47:43.147 に答える
38

複数のソース ファイルで使用される構造定義の場合は、必ずヘッダー ファイルに配置する必要があります。次に、構造を必要とするソース ファイルにそのヘッダー ファイルをインクルードします。

宣言は構造定義には使用されませんが、extern代わりに変数宣言 (つまり、定義した構造型を持つデータ値) に使用されます。複数のソース ファイルで同じ変数を使用する場合は、extern次のようにヘッダー ファイルで宣言します。

extern struct a myAValue;

次に、1 つのソース ファイルで、実際の変数を定義します。

struct a myAValue;

これを行うのを忘れたり、誤って 2 つのソース ファイルで定義した場合は、リンカによって通知されます。

于 2008-10-23T06:03:55.700 に答える
7

ああ:

#ifndef A_H
#define A_H

struct a { 
    int i;
    struct b {
        int j;
    }
};

#endif

これで、この構造を使用するファイルに ah を含めるだけで済みます。

于 2008-10-23T06:01:55.907 に答える