2

注意:これは宿題ではありません。プログラムは完全ではなく、完全には機能しませんが、少なくともコンパイルする必要があります。

私は、C Primer Plus Book を使用して独学でプロセスを進めている最中です (要するに、私は C の初心者です)。私は本全体をほぼ読み終え、各章の練習問題に取り組んでいます。これはそれらの時間の 1 つです。独特の問題に遭遇しましたが、それはプリプロセッサ ディレクティブに関連していると確信しています。

私は MinGW (Windows 用の gcc) を使用しており、次のように報告されます。

gcc が報告するエラーは次のとおりです。

nanfunct.c: 'keywords' の複数の定義
nanite.c: ここで最初に定義された
etc... etc... さらにエラーが発生しました...

これは複数のヘッダー ファイルが含まれていることが原因であると確信していますが、さらに重要なのは、私が作成してインクルードしたヘッダー ファイルがこの問題を引き起こしていることです。

この問題は、まだ事前定義されていない場合にのみ定義するように言っていますが、コンパイル時に複製される文字配列へのポインター (または文字列ベースの配列) にリンクしているようです。

例えば:

#ifndef MENU_OPTIONS
#   define MENU_OPTIONS ON
#   if MENU_OPTIONS == ON
        ...some code here...

        char * keywords[] = {
            "copy", "help", "line",
            "quit", "read", "write"
        };

        char * keyletters[] = {
            "c", "h", "l",
            "q", "r", "w"
        };
#   endif
#endif

私は3つのファイルを使用しています:

nanite.c -> main() の
ソース ファイル nanfunct.c -> 関数
nanproto.h のソース ファイル -> nanite.c および nanfunct.c のヘッダー ファイル

nanite.cとnanfunct.cの中にnanproto.h#include します

Pastebinに投稿されたソース ファイル:
nanproto.h -> nanite.cおよびnanfunct.cのヘッダー ファイル
nanite.c & nanfunct.c -> ソース ファイル

なぜこうなった?#ifndefは、このようなことが起こらないようにするためのものだと思いましたか?

4

2 に答える 2

4

プリプロセッサが何をするか、または C ソース ファイルがどのようにコンパイルおよびリンクされるかを誤解しています。

各ソース ファイルは個別に前処理されます。したがって、前処理の後、nanfunct.c にはkeywordsとの定義が含まれますkeyletters。前処理されたソースは、オブジェクト ファイル nanfunct.o にコンパイルされます。

前処理後、nanite.c にはkeywordsおよびの定義も含まれますkeyletters。この前処理されたソースは、オブジェクト ファイル nanite.o を生成するためにコンパイルされます。

次に、リンカーは nanfunct.o と nanite.o を結合しようとします。keywordsとの定義が複数あることが判明したkeylettersため、エラー メッセージを表示して中止します。

複数のソース ファイルで何かを利用できるようにする場合、通常のパターンは、宣言をヘッダー ファイルに配置し、定義を1 つのソース ファイルに配置することです。

これを動かします:

char * keywords[] = {
        "copy", "help", "line",
        "quit", "read", "write"
};

char * keyletters[] = {
        "c", "h", "l",
        "q", "r", "w"
};

nanite.cまたはnanfunct.c のいずれかに (両方ではない)。これらの宣言を nanite.hに追加します。

extern char * keywords[];
extern char * keyletters[];

そうすれば、定義は 1 つのオブジェクト ファイルにのみ含まれます。

これはグローバル変数と関数にのみ適用されることに注意してください。これらはオブジェクト ファイルに含まれていないため、構造体、共用体、列挙型、または型定義には適用されません。

于 2015-01-19T03:14:36.460 に答える
2

.h ファイルに定義を入れるのは間違いです。宣言のみが .h ファイルに入ります。

これを入れると(定義):

char * keywords[] = { "foo" };

.h ファイルで、それを複数の C ファイルにインクルードすると、#ifdef使用する ery の種類に関係なく、その変数がプロジェクト内の複数の場所で定義されることになります。

覚えておくべき重要なことは、各 .c ファイルが他のファイルとは独立してコンパイルされるということです。つまり#define、別の C ファイルで何かを実行したかどうかは関係ありません。

.h ファイルは次のようになります。

extern char *keywords[];

そして、正確に1 つの.c ファイルが定義を提供する必要があります。

于 2015-01-19T03:12:04.537 に答える