2

はじめに: 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 では、使用されていないデータは削除されず、使用されたコードのみが削除されるため、これは機能していました。

質問:単一のシンボルのみでこれを回避するにはどうすればよいですか?

4

1 に答える 1