web-dev-qa-db-ja.com

関数のC ++ externキーワード。ヘッダーファイルをインクルードしないのはなぜですか?

正しく理解できれば、これは

extern void foo();

関数fooが別の翻訳単位で宣言されていること。

1)この関数が宣言されているヘッダーを#includeするだけではどうですか?

2)リンク時に関数を探す場所をリンカーはどのように知るのですか?

編集:たぶん、上記の宣言の後に関数を使用することを明確にする必要があります

foo();

この翻訳単位で定義されることはありません。

43
user199421

1)ヘッダーファイルがない場合があります。しかし、はい、一般に、大規模なプロジェクトでは、複数の翻訳単位がその機能を使用する場合、ヘッダーファイルが必要です(繰り返しはしないでください)。

2)リンカは、関数やその他のシンボルを見つけるために通知されたすべてのオブジェクトファイルとライブラリを検索します。

27
Brian Neal

他の人がすでに述べたように、externキーワードは名前(変数または関数)が外部リンケージを持っていることを示すために使用されます。つまり、名前はプログラム全体の同じオブジェクトを参照します。また、これはファイルスコープで定義された変数と関数のデフォルトなので、この使用法は不要です。

次のようなexternキーワードの別の使用法があります。

extern "C" void foo();

これは、関数fooがリンクのC規則を使用してリンクされることを意味します(これは、Cライブラリで定義された関数であるか、Cプログラムによって呼び出されることを意図した関数であるためです)。

15
goedson

いいえ、これは、関数foo外部リンケージで宣言されていることを意味します。外部リンケージとは、名前fooがプログラム全体で同じ関数を指すことを意味します。関数が定義される場所は重要ではありません。この翻訳単位で定義できます。他の翻訳単位で定義できます。

例に示されているexternキーワードの使用は不要です。関数には、デフォルトで常に外部リンケージがあります。上記は100%と同等です

void foo();

リンカに関しては、リンカがプログラムをリンクすると、単にeverywhereに見えます。 fooの定義が見つかるまで、すべての定義を調べます。

15
AnT

Externキーワードなしで既にそれを意味します。関数は、静的に宣言しない限り、デフォルトで外部リンケージを持っています。

関数プロトタイプを使用しても問題ありませんが、間違えるのは簡単です。あなたが得るリンカエラーは、関数実装を再定義するときに診断するのはそれほど簡単ではありません。リンカはどこを見るべきかを知りません。関数定義を含むオブジェクトファイルを提供してそれを満足させるのはあなたの仕事です。

8
Hans Passant

1)なぜ機能にこれが必要なのかわかりません。他の誰かが介入できるかもしれません。

2)リンカは、すべてのオブジェクトファイルを調べて、各オブジェクトファイル内のシンボルをチェックすることにより、これを決定します。リンカに応じて、正確な検索順序は異なると思われます。

GNU binutils 'ldリンカのコマンドラインで、不足しているシンボルを含むオブジェクトが左から右に検索され、最初に見つかったシンボルが選択された後に表示されるすべてのオブジェクトファイルとライブラリ.

例1:

  • a.o-foo()、bar()を使用
  • liba-bar()を提供します
  • libb-foo()を提供します

$> ld a.o -la -lb

a.oで未定義のシンボルが検索されます。その後、ldはlibsを左から右に調べてこれらのシンボルを検索し、libaのbarとlibbのfooを見つけます。

これにより、循環依存関係に関する奇妙な問題が発生する場合があります。

例2:

  • a.o-bar()を使用
  • liba-bar()を提供し、foo()を使用します
  • libb-foo()を提供し、bar()を使用します

現在、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に、このグループに属するすべてのライブラリ内のすべてのシンボルを検索するように指示します。

2
BjoernD