5

構造体の二重宣言がコンパイルエラー引き起こすのに、関数の二重定義がリンクエラーを引き起こすのはなぜですか?

4

4 に答える 4

4

関数定義はリンク時に実行可能ファイルに含まれますが、デカレーションまたは構文チェックはすべてコンパイル時に行われます。

関数を呼び出していて、コンパイラが関数の宣言を見つけることができない場合にも、1つのことを考慮してください。そうすると、警告がとして生成されimplicit declaration of func()ます。

この警告メッセージを削除するために、funcの前方宣言を提供し、int func();警告メッセージなしでコンパイルしました。

なぜこれが起こると思いますか?func()これは、コンパイラがそのシンボルを見つけられなかったために発生します。言語の文法に従ってコードエラーをなくすのは、すべてコンパイラー次第です。

しかし、最終的な実行可能ファイルのビルドはリンク時に行われ、リンカーはの関数定義を探し始めfunc()ました。見つかった場合は問題なく、そうでない場合は..Linker error

could not have resolved external symbol _func()

注:外部シンボルはリンク時に解決されます

コンパイルのみのgccでは、これを使用します:(これはコンパイラによって異なる場合があります)

gcc -Werror -c test.c ->test.oファイルを生成します

次に、それをリンクして実行可能にしてみてください

gcc -Werror -o test test.o->test実行可能

于 2012-11-14T09:56:01.777 に答える
2

標準では、エラーをいつ報告する必要があるかは規定されていません。コンパイラ次第ですが、基本的には、エラーが検出されるのはそのためです

まず、コンパイラがファイルを解析します。structまたはclassが同じ翻訳単位で複数回定義されているかどうかを簡単に確認できます(これはエラーです。翻訳単位間では、複数のクラスタイプ定義を使用できます)。これは、その翻訳単位を処理するためです。

次に、オブジェクトファイルをリンクします(リンク)。同じシンボルが複数回エクスポートされたことがわかるのは今だけです。これは、たとえばエラーが発生したときだからです。

于 2012-11-14T10:01:18.550 に答える
2

プログラムをコンパイルするとき、コンパイラーは、使用する構造体の正確な定義を知る必要があります。ただし、プログラムをリンクしようとしているときにのみ、どの関数を使用するかを正確に知る必要があります。

したがって、構造体が2回定義されている場合、コンパイラはコンパイル中に混乱するため、コンパイル時に文句を言います。

コンパイル時の関数の場合、複数の定義を持つことができますが、混乱はリンク中にのみ発生するため、リンク中に文句を言います。

于 2012-11-14T10:01:33.343 に答える
1

あなたが言っていることは必ずしも真実ではありません。

関数定義をヘッダーに「インライン化」してから、その定義をコンパイルユニットに書き込むと、エラーが発生します。

...already has a definition.

参照しているのは、2つの異なるコンパイルユニットが同じ関数を定義(または定義を参照)している場合です。したがって、個々のコンパイルユニットにコンパイルエラーはなく、それらの組み合わせがリンクエラーの原因になります。

ちなみに、これはキーワードinlineが実際に違いを生む場所であることに注意してください。ヘッダーで定義されたテンプレート化されていない関数の場合、inlineキーワードを使用すると、この関数が定義された状態で複数のコンパイル単位が存在できることを意味します。コンパイラがインライン化することを実際に保証するものではありません。

于 2012-11-14T10:07:00.380 に答える