[解決済み] main関数の代わりにmainというグローバル変数があるプログラムはどのように動作するのでしょうか?
質問内容
次のようなプログラムを考えてみましょう。
#include <iostream>
int main = ( std::cout << "C++ is excellent!\n", 195 );
Windows 7 OS 上で g++ 4.8.1 (mingw64) を使用すると、プログラムは正常にコンパイルされ、印刷も実行されます。
C++は素晴らしいです!
をコンソールに表示します。
main
は関数ではなく、グローバル変数のように見えます。
main()
? このコードはC++の標準に準拠していますか?プログラムの動作はきちんと定義されていますか?また、私は
-pedantic-errors
オプションも使用しましたが、プログラムはまだコンパイルされ、実行されます。
どのように解決するのですか?
何が起こっているかという質問の本題に入る前に、プログラムが以下のように不正な形式であることを指摘することが重要です。 不具合報告 1886 にあるように、プログラムが不正な形式であることを指摘することが重要です。main() のための言語リンク :
[...] グローバルスコープで変数mainを宣言したり、C言語のリンクで(任意の名前空間で)mainという名前を宣言しているプログラムは不正な形式である。[...]
clangとgccの最新バージョンでは、これをエラーとし、プログラムはコンパイルされません( gcc の実例を見る ):
error: cannot declare '::main' to be a global variable
int main = ( std::cout << "C++ is excellent!\n", 195 );
^
では、なぜ古いバージョンのgccやclangでは診断がなかったのでしょうか。この不具合報告は2014年後半まで解決案すら出ていなかったので、このケースはごく最近になって明示的に診断が必要とされるようになったのです。
これに先立ち、これは、私たちが違反をしているので、未定義の動作になるようです。 とする
セクションの C++ 標準草案の要件に違反しているためです。3.6.1
[基本.開始.メイン]。
:
プログラムは、プログラムの開始を指定するmainと呼ばれるグローバル関数を含まなければならない。[...]
未定義の動作は予測不可能であり、診断の必要はありません。動作の再現で見られる不整合は、典型的な未定義の動作です。
では、コードは実際に何をしているのでしょうか、そしてなぜ場合によっては結果が出るのでしょうか。私たちが持っているものを見てみましょう。
declarator
| initializer----------------------------------
| | |
v v v
int main = ( std::cout << "C++ is excellent!\n", 195 );
^ ^ ^
| | |
| | comma operator
| primary expression
global variable of type int
私たちは
main
であり、これは
である。
グローバル名前空間で宣言され、初期化されている場合、その変数は静的な保存期間を持つ。を呼び出そうとする前に初期化が行われるかどうかは、実装で定義されています。
main
を呼び出す前に初期化を行うかどうかは実装で定義されていますが、 gcc ではこの初期化を行った後に
main
.
このコードでは
カンマ演算子
を呼び出すための副次的な効果としてのみ使用されています。
std::cout
. コンマ演算子の結果は右オペランドで、この場合は prvalue です。
195
であり、これが変数
main
.
私たちが見ることができるのは
が指摘するように
は、生成されたアセンブリを見ると
cout
が静的初期化中に呼び出されていることがわかります。しかし、議論する上でより興味深い点は
ゴッドボルトのライブセッションを見る
はこれでしょう。
main:
.zero 4
と続く。
movl $195, main(%rip)
考えられるシナリオは、プログラムがシンボル
main
という記号にジャンプし、そこに有効なコードがあることを期待し
でセグメンテーションエラーになる場合があります。
. もしそうなら、私たちは有効なマシンコードを変数
main
は
動作可能なプログラム
のように、コード実行が可能なセグメントに位置していると仮定します。私たちが見ることができるのは
この1984年のIOCCCのエントリ
は
ただそれだけ
.
C言語では、gccにこれをさせることができるようです( ライブを見る ):
const int main = 195 ;
これは、もし変数
main
が const でない場合、segment fault が発生します。これはおそらく実行可能な場所にないためと思われます。
コメント
にHat Tipして、このアイデアを得ました。
また FUZxxlの回答はこちら のC言語版もご覧ください。
関連
-
[解決済み】LLVMで暗黙のうちに削除されたコピーコンストラクタの呼び出し
-
[解決済み] 既に.objで定義されている-二重包含はない
-
[解決済み】「std::operator」で「operator<<」にマッチするものがない。
-
[解決済み】Visual Studio 2013および2015でC++コンパイラーエラーC2280「削除された関数を参照しようとした」が発生する
-
[解決済み】#include<iostream>は存在するのですが、「識別子 "cout "は未定義です」というエラーが出ます。なぜですか?
-
[解決済み】C++ - 適切なデフォルトコンストラクタがない [重複]。
-
[解決済み】C++ - ステートメントがオーバーロードされた関数のアドレスを解決できない。
-
[解決済み】Visual Studioのデバッガーエラー。プログラムを開始できません 指定されたファイルが見つかりません
-
[解決済み】f(i = -1, i = -1)の挙動が未定義なのはなぜ?
-
[解決済み] main()は本当にC++のプログラムの始まりなのか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン