1. ホーム
  2. c++

[解決済み] int main;' は有効なC/C++プログラムですか?

2022-10-22 01:46:53

質問

私はそう思っていないのですが、私のコンパイラはそう思っているようなので質問します。

echo 'int main;' | cc -x c - -Wall

echo 'int main;' | c++ -x c++ - -Wall

Clang はこれに対して警告もエラーも出さず、gcc は簡単な警告を出すだけです。 'main' is usually a function [-Wmain] ただし、C言語としてコンパイルされた場合のみです。 -std= を指定することは重要でないようです。

それ以外は、コンパイルもリンクもうまくいきます。しかし、実行時にはすぐに SIGBUS で終了してしまいます(私の場合)。

の(素晴らしい)回答に目を通すと CおよびC++でmain()は何を返すべきですか? での (素晴らしい) 回答と、言語仕様書をざっと読んでみると、確かに と思われます。 がメインであることは間違いないでしょう。 機能 が必要です。しかし、gccの文言は -Wmain ('main' は 通常 関数)(そして、ここでのエラーの少なさ)は、おそらくそうでないことを示唆しているようです。

しかし、なぜでしょうか?これには何か奇妙なエッジケースまたは「歴史的」な使い方があるのでしょうか。どなたか、何が原因かご存知ですか?

私が言いたいのは、私が本当にこれを エラー であるべきだということです。

どのように解決するのですか?

質問がCとC++のダブルタグになっているため、C++とCでは理由が異なるでしょう。

  • C++ では、リンカーが異なるタイプのテキスト的に同一のシンボル (たとえばグローバル変数) を区別できるようにするため、名前のマングリングを使用します。 xyz と独立したグローバル関数 xyz(int) . しかし、名前 main は決して揶揄されることはありません。
  • C ではマングリングを使用しないため、ある種のシンボルを別のシンボルの代わりに提供することによってリンカーを混乱させ、プログラムを正常にリンクさせることが可能です。

これがここで起こっていることです。リンカはシンボル main というシンボルが見つかるとリンカーは期待し、実際に見つかりました。リンカはそのシンボルをあたかも関数であるかのように配線しています。ランタイムライブラリのうち、制御を main をリンカに要求します。 main を要求しているので、リンカはそれにシンボル main を与え、リンクフェーズを完了させます。もちろん、これは実行時に失敗します。 main は関数ではないためです。

同じ問題の別の図解を示します。

ファイルx.c:

#include <stdio.h>
int foo(); // <<== main() expects this
int main(){
    printf("%p\n", (void*)&foo);
    return 0;
}

ファイルy.c:

int foo; // <<== external definition supplies a symbol of a wrong kind

をコンパイルします。

gcc x.c y.c

これはコンパイルされ、おそらく実行されるでしょうが、コンパイラに約束されたシンボルの型がリンカに供給された実際のシンボルと異なるため、未定義の動作となります。

警告に関しては、私は合理的だと思います。C 言語では main 関数を持たないライブラリを構築できるため、コンパイラは main を他の用途に使うことができます。 main を定義する必要がある場合です。