2011-02-02 7 views
19

this questionは、Cでmain()の前にコードを実行する方法を尋ねました。私は主にアプリケーションの空間に住んでいたので、main()の前に実行することは決して私には起こりませんでした。どのようなことがこの技術を必要としますか?main()の前にどのような操作を行う必要がありますか

+1

しないでください。 –

+3

これは面白かったです:http:// stackoverflow。com/questions/4783404/is-main-really-start-of-a-cプログラム – Dave

答えて

14

"どのようなことがこの技術を必要としていますか?"

ポイントオブファクト:なし。

しかし、さまざまな理由からメインの前にやりたいことがたくさんあります。具体的な例の1つとして、doohickiesを構築する抽象的な工場があるとします。あなたは工場のインスタンスを構築し、それをある特別な領域に割り当て、それに様々な具体的なdoohickiesを登録することができます...はい、あなたはそれを行うことができます。

一方、ファクトリをシングルトンとして実装し、グローバル値初期化のファクトを使用して実装を「トリック」して、メイン開始前に具体的なdoohickiesを登録すると、わずかなコストでいくつかの利点が得られます。シングルトンを使って、基本的にはここでは問題にはならないが、ほとんど唯一のものだ)。例えば

ます:

  1. すべてを明示的に呼び出す必要があります登録のリストを維持する必要はありません。実際には、クラス全体を宣言して定義することもできます。プライベートスコープでは誰の目にも見えず、プログラムの開始時に使用できるようにします。

  2. main()は気にしないオブジェクトをたくさん入れておく必要はありません。

ので、これのどれも実際に必要ではありません。しかし、メインが始まる前にグローバルが初期化されているという事実を利用すれば、結合とメンテナンスの問題を軽減できます。

編集:

は私がするので、これは言語によって保証されていないことを学んできたことを、ここで注意してください。C++は、が0であることを保証します。または定数 mainの前に初期化が行われます。この回答で私が話しているのは、の動的の初期化です。このC++の保証は、関数ローカルの静的変数によく似た、変数の最初の使用前に行われます。

すべてのコンパイラはメインの前に動的初期化を行っているようですが、私は一度それに遭遇したと思ったが、それは問題の原因が何か他のものだと私は信じている。

+0

+1これは私がこれを持っている唯一の使用ですが、少年は私がそれを使用しますか? –

5

この手法は、ライブラリ初期化ルーチンや、プログラムの実行中に暗黙的に使用されるデータの初期化に使用できます。


GCCは実行がmain()またはmain()完了したかexit()それぞれ呼ばれているに入る前に、関数が自動的に呼び出される原因となるfunction attributesコンストラクタデストラクタを提供します。ライブラリが実行時にロードされるか、ライブラリがロード時にロードされている場合main()前に開始された場合、ライブラリ初期化の場合

void __attribute__ ((constructor)) my_init(void); void __attribute__ ((destructor)) my_fini(void); 

は、コンストラクタルーチンはdlopen()戻る前に実行されます。ライブラリのクリーンアップに使用すると、デストラクタルーチンは、ライブラリが実行時にロードされる場合はdlclose()が返される前に実行され、exit()の場合はロードされ、ロード時にロードされる場合はmain()の完了後に返されます。

1

ライブラリをお持ちの場合は、main()が呼び出される前にいくつかのデータを初期化したりスレッドなどを作成したり、クライアントアプリケーションに負担をかけずに明示的に信頼することができます。ライブラリの初期化および/またはシャットダウンコードを呼び出します。表面的には、これはコンストラクタとデストラクタが必要な操作を実行する静的オブジェクトを持つことで実現できます。残念ながら、異なる翻訳単位またはライブラリ内の複数の静的オブジェクトは、定義されていない順序で初期化されるため、相互に依存する場合(さらに悪いことに、周期的な方法で)、依頼が到着する前に同様に、1つの静的オブジェクトはスレッドを作成し、まだスレッドセーフではない別のオブジェクトでサービスを呼び出すことがあります。だから、適切なシングルトンインスタンスとロックを持つより構造化されたアプローチが、任意の使用にもかかわらず堅牢性のために必要であり、全体的には魅力的ではありません。メイン前に行わ

3

スタッフ:x86では

  • 、スタック・ポインタ・レジスタは、4(アライメント)の倍数にするために通常& = 0XF3ある
  • 静的メンバーは
  • プッシュARGCを初期化されARGV(必要に応じて環境)
  • コール_main = P

グラム++ 4.4発する以下BEF私のコードはどれも放出されます。技術的にそれは私のコードのいずれかの前に、mainの最上部に挿入し、私はエントリポイントとして_initの代わり_mainを使用するコンパイラを見てきました:

.cfi_startproc 
.cfi_personality 0x3,__gxx_personality_v0 
pushq %rbp 
.cfi_def_cfa_offset 16 
movq %rsp, %rbp 
.cfi_offset 6, -16 
.cfi_def_cfa_register 6 
subq $16, %rsp 
movl %edi, -4(%rbp) 
movq %rsi, -16(%rbp) 
# My code follows 
3

mainが関与する前に、あなたがやりたいことができる唯一のものグローバル変数は悪いです。同じことは、遅延初期化(最初の使用時点での初期化)によって常に達成できます。もちろん、グローバル変数をまったく使用しないことで、よりうまくいくでしょう。

可能性のある「例外」は、実行時のグローバル定数テーブルの初期化です。しかし、これは非常に悪い習慣です。ライブラリー/プロセスのインスタンス間でテーブルを共有することはできません。ビルド時にstatic constテーブルをCまたはC++ソースファイルとして生成するスクリプトを書く方がずっと賢いです。

2

main開始後にコードの不変量を保証するコードを実行する必要があるものは、mainより前に実行する必要があります。

グローバルIostream、Cランタイムライブラリ、OSバインディングなどのようなものは、ほかの人が答えているようなコードを書く必要がありますか?

関連する問題