web-dev-qa-db-ja.com

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_オプションも使用しましたが、プログラムは引き続きコンパイルおよび実行されます。

97
Destructor

3.6.1/1から:

プログラムには、プログラムの指定された開始であるmainと呼ばれるグローバル関数が含まれます。独立した環境のプログラムがメイン機能を定義するために必要かどうかは、実装によって定義されます。

このことから、g​​ ++は、メイン関数なしで(おそらく「自立」節として)プログラムを許可するように見えます。

その後、3.6.1/3から:

関数mainはプログラム内で使用されません(3.2)。 mainのリンケージ(3.5)は実装定義です。 mainがインラインまたは静的であることを宣言するプログラムは不正です。それ以外の場合、メイン名は予約されていません。

したがって、ここでは、mainという名前の整数変数を持つことはまったく問題ないことを学びます。

最後に、出力が出力される理由を知りたい場合は、int mainは、コンマ演算子を使用して静的初期化でcoutを実行し、初期化を行うために実際の整数値を提供します。

20
Mark B

gcc 4.8.1は、次のx86アセンブリを生成します。

.LC0:
    .string "C++ is excellent!\n"
    subq    $8, %rsp    #,
    movl    std::__ioinit, %edi #,
    call    std::ios_base::Init::Init() #
    movl    $__dso_handle, %edx #,
    movl    std::__ioinit, %esi #,
    movl    std::ios_base::Init::~Init(), %edi  #,
    call    __cxa_atexit    #
    movl    $.LC0, %esi #,
    movl    std::cout, %edi #,
    call    std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)   #
    movl    $195, main(%rip)    #, main
    addq    $8, %rsp    #,
    ret
main:
    .zero   4

coutは、main関数ではなく、初期化中に呼び出されることに注意してください!

.zero 4は、mainから始まる4(0で初期化された)バイトを宣言します。ここで、mainvariable [!]の名前です。

mainシンボルは、プログラムの開始として解釈されます。動作はプラットフォームによって異なります。

9
sergej

それは不正なプログラムです。テスト環境cygwin64/g ++ 4.9.3でクラッシュします。

標準から:

.6.1メイン関数 [basic.start.main]

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

8
R Sahu

私がこれがうまくいくと思う理由は、compilermain()関数をコンパイルしていることを知らないので、グローバル整数をコンパイルします割り当ての副作用。

このtranslation-unitがコンパイルされるobject formatは使用できません関数シンボル変数シンボルの区別.

linkerは、(変数)mainシンボルにリンクし、処理します関数呼び出しのようです。しかし、runtime systemがグローバル変数初期化コードを実行するまではそうではありません。

サンプルを実行すると印刷されましたが、seg-faultが発生しました。 ランタイムシステムint変数を実行しようとしたときだと思います関数の場合

7
Galik

VS2013を使用してWin7 64ビットOSでこれを試しましたが、正しくコンパイルされますが、アプリケーションをビルドしようとすると、出力ウィンドウからこのメッセージが表示されます。

1>------ Build started: Project: tempTest, Configuration: Debug Win32 ------
1>LINK : fatal error LNK1561: entry point must be defined
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
4
Francis Cugler