なぜこれが機能するのか驚いていますか?
short main [] ={};
これはファイル内の唯一のコンテンツです。gccで正しくコンパイルされます。しかし、実行すると、セグメンテーション違反が出力されます。mainの名前を変更すると、コンパイラでエラーが発生します。誰かがここで何が起こっているのか私に説明できますか?
なぜこれが機能するのか驚いていますか?
short main [] ={};
これはファイル内の唯一のコンテンツです。gccで正しくコンパイルされます。しかし、実行すると、セグメンテーション違反が出力されます。mainの名前を変更すると、コンパイラでエラーが発生します。誰かがここで何が起こっているのか私に説明できますか?
明らかに、リンカはグローバルオブジェクトのタイプ(変数や関数など)を認識していませんが、アドレスのみを認識しています。したがって、変数が関数であるかのようにプログラムをリンクします。明らかな理由でクラッシュします。
このようなエラーが発生していますか?
Undefined symbols:
"_main", referenced from:
start in crt1.10.6.o
ld: symbol(s) not found
collect2: ld returned 1 exit status
これはコンパイラ エラーではなく、リンカ エラーです。
コンパイルでは、各ソース ファイルがオブジェクト ファイルに変換されます。
int main()
プログラムが複数のソースで構成されている可能性がありmain()
、これらのソースの 1 つだけで定義されているか、存在する必要さえない (動的ライブラリなど)ため、存在するかどうかのチェックはありません。ソースから
short main[] = {};
コンパイラによって有効な宣言 (short
名前付きのグローバル配列を作成main
し、空の配列に初期化する) と見なされるため、エラーは生成されません。
存在するかどうかの検出はint main()
、リンカによってチェックされます。リンカーは、コンパイルされたオブジェクト ファイルを実行可能な実行可能ファイルにバインドします。リンカがシンボルを見つけられない場合、main
上で説明したようなエラーが発生します。残念ながら、従来の C ABI は、関数やエクスポートされた変数の種類を区別していません。したがって、main
が配列として宣言されていても、リンカは「呼び出されたものmain
が存在する」ことしか認識しておらず、それ以上チェックできないため、同様にパスします。
その結果、間違った書き方をしているにもかかわらず、プログラムはエラーなく生成されます。
プログラムが実行されると、いわゆるmain
実行可能コードは保持されません。むしろ、それは単なるデータです (ゼロ化されている可能性があります)。したがって、システムは予期しないことを行う可能性があります(あなたの場合、それはSEGFAULTです)。
-Wall
これは、gcc でフラグを使用してコンパイルするときに実際にキャッチされる可能性があり、警告が表示されます。
<stdin>:1: warning: ‘main’ is usually a function
より多くのオプションでコンパイルしてみてください。:)
たとえば、単純な-Wallを追加します
gcc -Wall test.c -o t
test.c:1: warning: ‘main’ is usually a function
関連する標準ページを読んだことはありませんが、コンパイルするには、必ずしも関数ではなく、何らかのメインが必要なようです...