9

私は2つのソースファイルを持っています:

ソースファイル1(assembler.c):

#include "parser.c"
int main() {
    parse_file("test.txt");
    return 0;
}

ソースファイル2(parser.c):

void parse_file(char *config_file);
void parse_file(char *src_file) {
    // Function here
}

何らかの理由で、コンパイルすると次のエラーが発生します。 duplicate symbol _parse_file in ./parser.o and ./assembler.o for architecture x86_64

なぜparse_fileの重複シンボルが表示されるのですか?ここで関数を呼び出しているだけです...いいえ?

4

4 に答える 4

13

まず、ソースファイルを含めることはCプログラミングでは悪い習慣です。通常、現在の変換ユニットは、1つのソースファイルと多数のインクルードヘッダーファイルで構成されている必要があります。

あなたの場合、parse_file関数のコピーが2つあり、各翻訳単位に1つずつあります。がparser.cオブジェクトファイルにコンパイルされると、独自の機能があり、独自のparse_file機能assembler.cもあります。

入力として2つのオブジェクトファイルが与えられたときに(コンパイラではなく)文句を言うのはリンカであり、それぞれに独自の定義が含まれていますparse_file

次のようにプロジェクトを再構築する必要があります。

parser.h

void parse_file(char *);

parser.c

void parse_file(char *src_file) {
    // Function here
}

assembler.c

/* note that the header file is included here */
#include "parser.h"

int main (void) {
    parse_file("test.txt");
    return 0;
}
于 2011-10-03T18:16:28.740 に答える
8

parser.cファイルをインクルードします。これは、そのファイルに含まれるすべてのコードがassembler.cファイルに「コピー」されることを意味します。つまり、parser.cの内容全体は、コンパイラーがparser.cをコンパイルしているときにコンパイルされ、コンパイラーがassembler.cをコンパイルしているときに再度コンパイルされます。

それがヘッダーの目的です。
ヘッダーには宣言のみを含めることができるため、同じシンボルを別の変換単位で再度作成しなくても、宣言を含めることができます。

したがって、関数の宣言だけを含むparser.hを作成できます。

void parse_file(char *config_file);

次に、assembler.cにヘッダーのみを含めます。

#include "parser.h" //include the header, not the implementation
int main() {
    parse_file("test.txt");
    return 0;
}
于 2011-10-03T18:13:54.933 に答える
3

関数parse_fileの定義を含む.cファイルを含めています。したがって、各翻訳単位で1回ずつ、2回定義されますが、これは許可されていません。

于 2011-10-03T18:14:56.583 に答える
2

他の回答が述べているように、ソースを含めると、ファイルはparser.cにコピーされ、元の場所(assembler.c)でも定義されます。これを解決するには、プロトタイプを使用してヘッダーファイルを作成します。

parser.h

void parse_file(char *config_file);

そして、そのファイルを含めます。

assembler.c

#include "parser.h"
int main() {
    parse_file("test.txt");
    return 0;
}

または、インクルードを削除して、関数の手がかりを提供します。

int main() {
    void parse_file(char *);
    parse_file("test.txt");
    return 0;
}

または、単にインクルードを削除することもできます。コンパイラー(関数に関する情報なし)は戻り値が整数であると見なし、他の警告を引き起こす可能性があるため、お勧めできません。

于 2011-10-03T18:21:42.610 に答える