正しく理解できれば、これは
extern void foo();
関数fooが別の翻訳単位で宣言されていること。
1)この関数が宣言されているヘッダーを#includeするだけではどうですか?
2)リンク時に関数を探す場所をリンカーはどのように知るのですか?
編集:たぶん、上記の宣言の後に関数を使用することを明確にする必要があります
foo();
この翻訳単位で定義されることはありません。
1)ヘッダーファイルがない場合があります。しかし、はい、一般に、大規模なプロジェクトでは、複数の翻訳単位がその機能を使用する場合、ヘッダーファイルが必要です(繰り返しはしないでください)。
2)リンカは、関数やその他のシンボルを見つけるために通知されたすべてのオブジェクトファイルとライブラリを検索します。
他の人がすでに述べたように、extern
キーワードは名前(変数または関数)が外部リンケージを持っていることを示すために使用されます。つまり、名前はプログラム全体の同じオブジェクトを参照します。また、これはファイルスコープで定義された変数と関数のデフォルトなので、この使用法は不要です。
次のようなexternキーワードの別の使用法があります。
extern "C" void foo();
これは、関数foo
がリンクのC規則を使用してリンクされることを意味します(これは、Cライブラリで定義された関数であるか、Cプログラムによって呼び出されることを意図した関数であるためです)。
いいえ、これは、関数foo
が外部リンケージで宣言されていることを意味します。外部リンケージとは、名前foo
がプログラム全体で同じ関数を指すことを意味します。関数が定義される場所は重要ではありません。この翻訳単位で定義できます。他の翻訳単位で定義できます。
例に示されているextern
キーワードの使用は不要です。関数には、デフォルトで常に外部リンケージがあります。上記は100%と同等です
void foo();
リンカに関しては、リンカがプログラムをリンクすると、単にeverywhereに見えます。 foo
の定義が見つかるまで、すべての定義を調べます。
Externキーワードなしで既にそれを意味します。関数は、静的に宣言しない限り、デフォルトで外部リンケージを持っています。
関数プロトタイプを使用しても問題ありませんが、間違えるのは簡単です。あなたが得るリンカエラーは、関数実装を再定義するときに診断するのはそれほど簡単ではありません。リンカはどこを見るべきかを知りません。関数定義を含むオブジェクトファイルを提供してそれを満足させるのはあなたの仕事です。
1)なぜ機能にこれが必要なのかわかりません。他の誰かが介入できるかもしれません。
2)リンカは、すべてのオブジェクトファイルを調べて、各オブジェクトファイル内のシンボルをチェックすることにより、これを決定します。リンカに応じて、正確な検索順序は異なると思われます。
GNU binutils 'ldリンカのコマンドラインで、不足しているシンボルを含むオブジェクトが左から右に検索され、最初に見つかったシンボルが選択された後に表示されるすべてのオブジェクトファイルとライブラリ.
例1:
$> ld a.o -la -lb
a.oで未定義のシンボルが検索されます。その後、ldはlibsを左から右に調べてこれらのシンボルを検索し、libaのbarとlibbのfooを見つけます。
これにより、循環依存関係に関する奇妙な問題が発生する場合があります。
例2:
現在、libaとlibbの間には循環依存関係があり、リンクは失敗します。
$> ld a.o -la -lb
なぜなら、libbの未定義のシンボルを検索すると、ldはこのシンボルを提供する他のlib -lbの右側がないと判断するからです。これは、少なくとも2つの方法で修正できます。
1)libaを2回リンク:$> ld a.o -la -lb -la
2)ldのグループ化機能を使用$> ld a.o --start-group -la -lb --end-group
ケース2)では、グループ化はldに、このグループに属するすべてのライブラリ内のすべてのシンボルを検索するように指示します。