質問

C ++標準の読み取りからのセクション$ 3.6.1/1

プログラムには、呼ばれるグローバル関数が含まれているものとします 主要, 、指定されたものです 始める プログラムの。

このコードを考慮してください、

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に印刷することを行います。 に入る main() プログラムの「開始」であると思われる関数。

私もそれを編集しました -pedantic オプション、GCC 4.5.0。それはエラーを与えず、警告さえしません!

だから私の質問は、

このコードは本当に標準的な立場ですか?

標準的なコンフォーマルである場合、標準が言っていることを無効にしませんか? main() このプログラムの開始ではありません! user_main() の前に実行されました main().

グローバル変数を初期化することを理解しています main_ret, 、 use_main() 最初に実行しますが、それはまったく別のことです。ポイントは、それです します 引用されたステートメントを標準から3.6.1/1 $ 3.6.1/1に無効にします。 main() そうではありません 始める プログラムの;それは実際にです 終わりこれ プログラム!


編集:

「Start」という言葉をどのように定義しますか?

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

役に立ちましたか?

解決

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

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

メインの後、あなたのコードは、プログラムの概念的に「完全に制御されている」ことがあります。これは、実行する命令とそれらを実行する順序を指定できるという意味でです。マルチスレッドは、コード実行順序を再配置できます。ただし、コードのセクションが(おそらく)順序外で実行されるように指定されているため、まだC ++でコントロールされています。

他のヒント

あなたは文を誤って読んでいます。

プログラムには、Mainと呼ばれるグローバル関数が含まれているものとします。 これがプログラムの指定された開始です。

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

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

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

プログラムはリンクせず、メインがない限り実行されません。ただし、ファイルレベルのオブジェクトには事前に実行されるコンストラクターがあり、Main()に到達する前に寿命を実行するプログラム全体を作成し、Main自体がメイン自体を持つことができるため、Main()はプログラムの実行の開始を引き起こしません。空の体。

実際には、これを実施するには、メインとそのコンストラクターの前に構築されたオブジェクトが1つあり、プログラムのすべてのフローを呼び出す必要があります。

これを見てください:

class Foo
{
public:
   Foo();

 // other stuff
};

Foo foo;

int main()
{
}

プログラムの流れは効果的に生じます Foo::Foo()

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

この場合に最も関連性の高いのは、制約#4のようです。

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

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

C ++標準のみに興味がある場合は、おそらく「C」タグを削除したいと思うでしょう。

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

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

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

標準は、これらの変数が「魔法」によって初期化されていると仮定しています。 どうやって プログラムの初期化の前に設定する必要があります。彼らはそれをプログラミング言語標準の範囲外の何かと考えていると思います。

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

静的ストレージ期間のすべてのオブジェクトは、プログラムの起動前に初期化され(初期値に設定されています)ものでなければなりません。そのような初期化の方法とタイミングは、それ以外の場合は特定されていません。

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

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

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

したがって、ほとんどすべてのC/C ++プログラムには、標準の初期化ルールに準拠するために、メインが呼び出される前に実行されるINIT/「コピーダウン」コードがあります。

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

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

Main()は、C Runtime Libraryによって呼び出されるユーザー関数です。

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

英語のセマンティクスがquiむように思えます。 OPは、最初に彼のコードブロックを「コード」と呼び、後に「プログラム」と呼びます。ユーザーはコードを書き込み、コンパイラがプログラムを書き込みます。

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

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

はい、メインは、実装固有の拡張機能を除き、すべてのC ++プログラムの「エントリポイント」です。それでも、Main_retのように、いくつかのことがメインの前、特にグローバルな初期化が行われます。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top