どのような状況下で、GCCがnotメイクアップ関数を呼び出そうとしたときに「未定義の参照」リンクエラーメッセージをスローすることができますか?
たとえば、このCコードがGCCによってコンパイルおよびリンクされる状況:
void function()
{
made_up_function_name();
return;
}
... made_up_function_name
は存在しませんがanywhereはコード内にあります(ヘッダー、ソースファイル、宣言、サードパーティライブラリではありません)。
そのようなコードは、実際のコードに触れることなく、特定の条件下でGCCによって受け入れられ、コンパイルされますか?もしそうなら、どれ?
ありがとう。
編集:made_up_function_name
への以前の宣言または言及は、他のどこにも存在しません。つまり、ファイルシステム全体のgrep -R
がonlyのコードの正確な単一行を表示するということです。
はい、未定義の参照の報告を避けることができます---unresolved-symbols
リンカーオプションを使用します。
g++ mm.cpp -Wl,--unresolved-symbols=ignore-in-object-files
man ld
から
-unresolved-symbols = method
未解決のシンボルの処理方法を決定します。 methodには次の4つの値があります。
ignore-all Do not report any unresolved symbols. report-all Report all unresolved symbols. This is the default. ignore-in-object-files Report unresolved symbols that are contained in shared libraries, but ignore them if they come from regular object files. ignore-in-shared-libs Report unresolved symbols that come from regular object files, but ignore them if they come from shared libraries. This can be useful when creating a dynamic binary and it is known that all the shared libraries that it should be referencing are included on the linker's command line.
共有ライブラリ自体の動作は、-[no-] allow-shlib-undefinedオプションによって制御することもできます。
通常、リンカは報告された未解決のシンボルごとにエラーメッセージを生成しますが、オプション--warn-unresolved-symbolsはこれを警告に変更できます。
関数を使用する前に関数のプロトタイプを宣言すると、コンパイルが保留されます。とにかくリンク中のエラーは残ります。
void made_up_function_name();
void function()
{
made_up_function_name();
return;
}
TL; DR Itcan文句を言わないが、あなたはdo n'tそれが欲しい。リンカーに問題を無視させると、コードがクラッシュします。逆効果になるでしょう。
あなたのコードは古代のC(pre-C99)に依存しており、関数が使用時に暗黙的に宣言されることを可能にします。コードは、次のコードと意味的に同等です:
_void function()
{
int made_up_function_name(...); // The implicit declaration
made_up_function_name(); // Call the function
return;
}
_
リンカは、コンパイルされたfunction()
を含むオブジェクトファイルが他のどこにも見つからなかったシンボルを参照していることを正当に訴えます。修正する必要があります-実装を提供する for made_up_function_name()
または無意味な呼び出しを削除する。それだけです。リンカーをいじる必要はありません。
そして、GCCに渡される-Dフラグには、この厄介さがあります。
$cat undefined.c
void function()
{
made_up_function_name();
return;
}
int main(){
}
$gcc undefined.c -Dmade_up_function_name=atexit
$
Made_up_function_nameの定義を探すことを想像してみてください。コードのどこにも「何かをする」ようには見えません。コードでこの正確なことをする良い理由は考えられません。
-Dフラグは、コンパイル時にコードを変更するための強力なツールです。
function()
が呼び出されない場合、実行可能ファイルに含まれていない可能性があり、そこから呼び出された関数も検索されません。
リンカフラグ-r
または--relocatable
を使用してビルドすると、「未定義の参照」リンクエラーメッセージも生成されません。
これは、-r
が新しいオブジェクトファイル内の異なるオブジェクトをリンクし、後の段階でリンクするためです。
POSIXリンカが動作する「標準」アルゴリズムでは、コードがエラーなしでコンパイルおよびリンクされる可能性がありません。詳細については、こちらをご覧ください: https://stackoverflow.com/a/11894098/18769
その可能性を活用するには、function
を含むオブジェクトファイル(それをf.o
と呼びましょう)をライブラリに配置する必要があります。そのライブラリーは、コンパイラー(および/またはリンカー)のコマンドラインで言及する必要がありますが、その時点では、他のオブジェクトファイル(コマンドラインで前述)がfunction
またはその他の呼び出しを行ってはなりません。 f.o
に存在する関数。このような状況では、リンカーはライブラリからf.o
を取得する理由を認識しません。リンカーはf.o
を完全に無視し、function
を完全に無視するため、made_up_function_name
の呼び出しを完全に無視します。 made_up_function_name
がどこにも定義されていない場合でも、コードはコンパイルされます。