init_seg
pragma
C++ 固有
スタートアップ コードが実行される順序に影響を与えるキーワードまたコード セクションを指定します。
構文
#pragma init_seg(
{compiler
|lib
|user
|"section-name" [,
func-name ] })
解説
この記事では、セグメントとセクションという用語の意味は同じです。
グローバル静的オブジェクトを初期化するためにコードが必要になることがあるため、いつオブジェクトを構築するかを指定する必要があります。 特に、重要なのは init_seg
pragma を、ダイナミック リンク ライブラリ (DLL) で、または初期化が必要なライブラリで使用することです。
init_seg
pragma に対するオプションは次のとおりです。
compiler
Microsoft C ランタイム ライブラリの初期化のために予約されています。 このグループ内のオブジェクトが最初に構築されます。
lib
サード パーティの開発元のクラス ライブラリの初期化に使用できます。 このグループのオブジェクトは、compiler
としてマークされているものの後、しかし他のすべてのものより先に構築されます。
user
ユーザーが使用できます。 このグループ内のオブジェクトが最後に構築されます。
section-name
初期化セクションの明示的な指定を許可します。 ユーザー指定の section-name のオブジェクトは、暗黙的に構築されません。 ただし、それらのアドレスは、section-name によって名前が付けられたセクションに置かれます。
指定する section-name には、そのモジュール内の pragma の後で宣言されたグローバル オブジェクトを構築するヘルパー関数へのポインターが格納されます。
セクションを作成する場合に使用しない名前のリストについては、「/SECTION
」を参照してください。
func-name
プログラムの終了時に atexit
の代わりに呼び出される関数を指定します。 このヘルパー関数は atexit
も呼び出して、グローバル オブジェクトのデストラクターへのポインターを渡します。 次の形式の pragma で関数の識別子を指定した場合、
int __cdecl myexit (void (__cdecl *pf)(void))
指定した関数が C ランタイム ライブラリの atexit
の代わりに呼び出されます。 これにより、オブジェクトを破棄する準備ができたとき呼び出すデストラクターのリストを作成できます。
初期化を遅延する必要がある場合 (たとえば、DLL 内で) セクション名を明示的に指定することもできます。 コードがその後に各静的オブジェクトのコンストラクターを呼び出す必要があります。
atexit
の代わりとなる関数は引用符で囲みません。
それでも、オブジェクトは他の XXX_seg
pragma ディレクティブで定義されたセクションに配置されます。
モジュール内で宣言されたオブジェクトは、C ランタイムにより自動的に初期化されません。 コードが初期化を行う必要があります。
既定では、init_seg
セクションは読み取り専用です。 セクション名が .CRT
の場合、属性が読み取り/書き込み可能としてマークされている場合でも、属性はコンパイラによって通知なしで読み取り専用に変更されます。
init_seg
を 1つの翻訳単位で複数回指定することはできません。
オブジェクトが、コード内で明示的に定義された、ユーザー定義コンストラクターを持っていない場合でも、コンパイラはそれを生成してくれることがあります。 たとえば、v テーブル ポインターをバインドするためにそれを作成してくれる場合があります。 必要に応じて、コードがコンパイラによって生成されたコンストラクターを呼び出します。
例
// pragma_directive_init_seg.cpp
#include <stdio.h>
#pragma warning(disable : 4075)
typedef void (__cdecl *PF)(void);
int cxpf = 0; // number of destructors we need to call
PF pfx[200]; // pointers to destructors.
int myexit (PF pf) {
pfx[cxpf++] = pf;
return 0;
}
struct A {
A() { puts("A()"); }
~A() { puts("~A()"); }
};
// ctor & dtor called by CRT startup code
// because this is before the pragma init_seg
A aaaa;
// The order here is important.
// Section names must be 8 characters or less.
// The sections with the same name before the $
// are merged into one section. The order that
// they are merged is determined by sorting
// the characters after the $.
// InitSegStart and InitSegEnd are used to set
// boundaries so we can find the real functions
// that we need to call for initialization.
#pragma section(".mine$a", read)
__declspec(allocate(".mine$a")) const PF InitSegStart = (PF)1;
#pragma section(".mine$z",read)
__declspec(allocate(".mine$z")) const PF InitSegEnd = (PF)1;
// The comparison for 0 is important.
// For now, each section is 256 bytes. When they
// are merged, they are padded with zeros. You
// can't depend on the section being 256 bytes, but
// you can depend on it being padded with zeros.
void InitializeObjects () {
const PF *x = &InitSegStart;
for (++x ; x < &InitSegEnd ; ++x)
if (*x) (*x)();
}
void DestroyObjects () {
while (cxpf>0) {
--cxpf;
(pfx[cxpf])();
}
}
// by default, goes into a read only section
#pragma init_seg(".mine$m", myexit)
A bbbb;
A cccc;
int main () {
InitializeObjects();
DestroyObjects();
}
A()
A()
A()
~A()
~A()
~A()