はじめに: C++ のグローバルな静的オブジェクトは、main()
開始前に初期化されます。検討:
#include <stdio.h>
int calc_it() {
return 1;
}
int glob = calc_it();
int main() {
printf("glob = %d\n", glob);
return 0;
}
および割り当てが開始前に実行されるglob = 1
ため、出力はです。コードの順序は関係ありません。calc_it()
main()
ここで、そのようなコードを含む複数のソース ファイルがあり、さらにそれらが相互に依存していると想像します (何らかの理由で、特定の実行順序が必要です。それが良い設計か悪い設計かについては触れません)。
実行の順序は標準では定義されていませんが、Visual C++ でそれらに特定の順序を課す方法は存在します。グローバルな静的オブジェクトの場合、オブジェクト定義の前に使用#pragma init_seg(SECTIONNAME)
して、特定のセクション名を指定できます。
しかし、最終的にこれは、コンパイラ(__cdecl *)(void)
が特定のリンカ セクション (すべて で始まる.CRT$XC
) の関数へのポインタを配置することにつながるだけです。セクション名は、リンカーによってメモリ レイアウトが決定される前に、辞書順に並べられます。デフォルトのセクション名は.CRT$XCU
. 次に、C/C++ の初期化コードは、 と の間のこれらのセグメントの内容を関数へのポインター.CRT$XCA
と見なし、.CRT$XCZ
それらを 1 つずつ呼び出します。
#pragma data_seg(SECTIONNAME)
これは、ディレクティブを使用して手動で行うこともできます。したがって、この:
#include <stdio.h>
void hi_there() {
printf("hi there!\n");
}
int main() {
printf("bye!\n");
return 0;
}
#pragma data_seg(".CRT$XCM")
typedef void (__cdecl *atexit_func)(void);
atexit_func _init_ptr[] = { hi_there };
出力します:
hi there!
bye!
それはどれほどいいですか?:)
問題の説明:
私の知る限り、Visual C++ 2015 以降、/GL
オプション (プログラム全体の最適化) を/OPT:REF
リンカー オプション (未使用の関数とデータを削除する) と一緒に使用すると、これは機能しなくなります。その理由は、リンカの観点から、_init_ptr
が使用されないことが原因である可能性があります。古いバージョンの Visual Studio では、使用されていないデータは削除されず、使用されたコードのみが削除されるため、これは機能していました。
質問:単一のシンボルのみでこれを回避するにはどうすればよいですか?