web-dev-qa-db-ja.com

GCCは未定義の参照について文句を言うことはできませんか?

どのような状況下で、GCCがnotメイクアップ関数を呼び出そうとしたときに「未定義の参照」リンクエラーメッセージをスローすることができますか?

たとえば、このCコードがGCCによってコンパイルおよびリンクされる状況:

void function()
{
    made_up_function_name();
    return;
}

... made_up_function_nameは存在しませんがanywhereはコード内にあります(ヘッダー、ソースファイル、宣言、サードパーティライブラリではありません)。

そのようなコードは、実際のコードに触れることなく、特定の条件下でGCCによって受け入れられ、コンパイルされますか?もしそうなら、どれ?

ありがとう。

編集:made_up_function_nameへの以前の宣言または言及は、他のどこにも存在しません。つまり、ファイルシステム全体のgrep -Ronlyのコードの正確な単一行を表示するということです。

49
STenyaK

はい、未定義の参照の報告を避けることができます---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はこれを警告に変更できます。

84
Dmitry Yudakov

関数を使用する前に関数のプロトタイプを宣言すると、コンパイルが保留されます。とにかくリンク中のエラーは残ります。

void made_up_function_name();
void function()
{
    made_up_function_name();
    return;
}
3
Heisenbug

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()または無意味な呼び出しを削除する。それだけです。リンカーをいじる必要はありません。

2
Kuba Ober

そして、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フラグは、コンパイル時にコードを変更するための強力なツールです。

2
Tim Williscroft

function()が呼び出されない場合、実行可能ファイルに含まれていない可能性があり、そこから呼び出された関数も検索されません。

1
Bo Persson

リンカフラグ-rまたは--relocatableを使用してビルドすると、「未定義の参照」リンクエラーメッセージも生成されません。

これは、-rが新しいオブジェクトファイル内の異なるオブジェクトをリンクし、後の段階でリンクするためです。

1
Sjors Telgen

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がどこにも定義されていない場合でも、コードはコンパイルされます。

0
AnT