web-dev-qa-db-ja.com

main()は実際にC ++プログラムの開始ですか?

C++標準のセクション$ 3.6.1/1は、

プログラムには、プログラムの指定されたstartであるmainと呼ばれるグローバル関数が含まれます。

次に、このコードを検討します。

_int square(int i) { return i*i; }
int user_main()
{ 
    for ( int i = 0 ; i < 10 ; ++i )
           std::cout << square(i) << endl;
    return 0;
}
int main_ret= user_main();
int main() 
{
        return main_ret;
}
_

このサンプルコードは、私が意図したことを行います。つまり、0から9までの整数の2乗を出力します。beforeは、「開始」となるmain()関数に入りますプログラムの。

また、GCC 4.5.0の_-pedantic_オプションでコンパイルしました。エラーも警告もありません!

私の質問は

このコードは本当に標準に準拠していますか?

それが標準に準拠している場合、標準が言っていることを無効にしませんか? main()はこのプログラムの開始ではありません! user_main()の前に実行されるmain()

グローバル変数_main_ret_を初期化するために、use_main()が最初に実行されることを理解していますが、それはまったく別のものです。要点は、それはdoes標準の引用文$ 3.6.1/1を無効にします。main()startプログラムの;実際には- ofthisプログラムです!


編集:

Wordの「開始」をどのように定義しますか?

フレーズ「プログラムの開始」の定義に要約されます。では、どのように正確に定義しますか?

130
Nawaz

いいえ、C++はmainを呼び出す前に「環境を設定する」ために多くのことを行います。ただし、mainは、C++プログラムの「ユーザー指定」部分の公式な開始点です。

一部の環境設定は制御できません(std :: coutを設定する初期コードなど)。ただし、一部の環境は(静的グローバル変数を初期化するための)静的グローバルブロックのように制御可能です。 mainの前に制御すると、静的ブロックが初期化される順序を完全に制御することはできません。

Mainの後、実行する命令と実行する順序の両方を指定できるという意味で、コードは概念的にプログラムを「完全に制御」しています。マルチスレッドは、コードの実行順序を並べ替えることができます。ただし、コードのセクションを(場合によっては)順不同で実行するように指定したため、C++を使用して制御できます。

82
Edwin Buck

あなたは文章を間違って読んでいます。

プログラムには、プログラムの指定された開始であるmainと呼ばれるグローバル関数が含まれます。

標準は、残りの標準のために「開始」という言葉を定義しています。 mainが呼び出される前にコードが実行されないということではありません。プログラムの開始は関数mainにあると見なされると書かれています。

プログラムは準拠しています。 mainが開始されるまで、プログラムは「開始」されていません。コンストラクターは、標準の「開始」の定義に従ってプログラムが「開始」する前に呼び出されますが、それはほとんど問題ではありません。この例だけでなく、すべてのプログラムでmaineverが呼び出される前に、大量のコードが実行されます。

説明のために、コンストラクタコードはプログラムの「開始」前に実行され、標準に完全に準拠しています。

87
Adam Davis

プログラムはリンクされないため、メインがない限り実行されません。ただし、ファイルレベルのオブジェクトには事前に実行されるコンストラクターがあり、main()に到達する前にその寿命を実行するプログラム全体を記述し、main自体に空の体。

これを強制するには、プログラムのすべてのフローを呼び出すために、mainとそのコンストラクターの前に構築される1つのオブジェクトが必要です。

これを見てください:

_class Foo
{
public:
   Foo();

 // other stuff
};

Foo foo;

int main()
{
}
_

プログラムのフローは、実質的にFoo::Foo()から生じます。

23
CashCow

質問に「C」というタグを付けた後、厳密にCについて言えば、ISO C99標準のセクション6.7.8「初期化」に従って初期化が失敗するはずです。

この場合に最も関連するのは、次のような制約#4のようです。

静的ストレージ期間を持つオブジェクトの初期化子のすべての式は、定数式または文字列リテラルでなければなりません。

したがって、あなたの質問に対する答えは、コードがC標準に準拠していないということです。

C++標準のみに関心がある場合は、「C」タグを削除することをお勧めします。

15
Remo.D

セクション3.6全体は、mainと動的初期化の相互作用について非常に明確です。 「プログラムの指定された開始」は他のどこでも使用されず、main()の一般的な意図を説明するだけです。標準のより詳細で明確な要件と矛盾する規範的な方法でその1つのフレーズを解釈することは意味がありません。

10
aschepler

コンパイラは、多くの場合、main()の前にbe標準準拠のコードを追加する必要があります。標準では、グローバル/静的の初期化を行う必要があると規定されているため、beforeが実行されます。前述のように、ファイルスコープ(グローバル)に配置されたオブジェクトのコンストラクターについても同じことが言えます。

したがって、元の質問isはCにも関連しています。Cプログラムでは、プログラムを開始する前にグローバル/静的初期化を行う必要があるためです。

標準では、これらの変数はhowとは言わないため、プログラムの初期化の前に設定する必要があるため、これらの変数は「マジック」によって初期化されると想定しています。彼らはそれをプログラミング言語標準の範囲外のものと考えていたと思います。

編集:たとえば、ISO 9899:1999 5.1.2を参照してください:

静的ストレージ期間を持つすべてのオブジェクトは、プログラムの起動前に初期化(初期値に設定)する必要があります。それ以外の場合、このような初期化の方法とタイミングは指定されていません。

この「魔法」がどのように行われたのかという理論は、RAMベースのコンピューターでUNIX OS専用に使用されるプログラミング言語であったCの誕生にまでさかのぼります。理論的には、プログラム自体がRAMにアップロードされると同時に、プログラムはすべての事前初期化済みデータを実行可能ファイルからRAMにロードできます。

それ以来、コンピューターとOSが進化し、Cは当初予想されていたよりもはるかに広い領域で使用されています。最新のPC OSには仮想アドレスなどがあり、すべての組み込みシステムはRAMではなくROMからコードを実行します。したがって、RAMを「自動的に」設定できない状況が多くあります。

また、標準は抽象的すぎてスタックやプロセスメモリなどについて何も知ることができません。これらのことも、プログラムを開始する前に行う必要があります。

したがって、ほとんどすべてのC/C++プログラムには、標準の初期化ルールに準拠するために、mainが呼び出される前に実行されるinit/"copy-down"コードがあります。

例として、組み込みシステムには通常、「非ISO準拠のスタートアップ」と呼ばれるオプションがあり、パフォーマンス上の理由で初期化フェーズ全体がスキップされ、コードは実際にはmainから直接開始されます。ただし、グローバル/静的変数の初期値に依存することはできないため、このようなシステムは標準に準拠していません。

9
Lundin

main()は、Cランタイムライブラリによって呼び出されるユーザー関数です。

参照: Cプログラムのメイン(エントリポイント)の回避

4
sylvanaar

「プログラム」は、単にグローバル変数から値を返します。それ以外はすべて初期化コードです。したがって、標準が保持されます-非常に簡単なプログラムとより複雑な初期化だけがあります。

4
Zac Howland

英語のセマンティクスのbのようです。 OPは、彼のコードブロックを最初に「コード」と呼び、後に「プログラム」と呼びます。ユーザーがコードを記述してから、コンパイラーがプログラムを記述します。

2
dSerk

mainは、すべてのグローバル変数を初期化した後に呼び出されます。

標準で指定されていないのは、すべてのモジュールおよび静的にリンクされたライブラリのすべてのグローバル変数の初期化の順序です。

1
vz0

はい。mainは、実装固有の拡張機能を除き、すべてのC++プログラムの「エントリポイント」です。それでも、mainの前に、特にmain_retなどのグローバルな初期化が発生します。

0
Fred Nurk