C言語でプログラムを開発している際に、コンパイルの最終段階で「undefined reference to ‘main’」というエラーメッセージが表示され、ビルドが停止してしまうことがあります。

このエラーは、プログラムの実行を開始するための起点となる「main関数」をリンカが見つけられなかったことを意味しています。

初心者にとってはコードの中にmain関数を書いたつもりでも発生するため、非常に混乱しやすいエラーの一つと言えるでしょう。

本記事では、このエラーが発生する根本的なメカニズムを解明し、シチュエーション別の具体的な解決策を詳しく提示します。

undefined reference to ‘main’ エラーの正体

このエラーは、正確にはコンパイルエラーではなく、リンカ(Linker)と呼ばれるプログラムが発生させるエラーです。

C言語のビルドプロセスは、ソースコードを解析する「コンパイル」と、生成されたオブジェクトファイルを結合する「リンク」の二段階に分かれています。

リンカは、実行ファイルを作成するためにプログラムの開始地点となるmain関数を探索します。

しかし、プロジェクト全体をスキャンしてもmainという名前のシンボルが見つからない場合、このエラーが出力されます。

つまり、ソースコードに文法的な誤りがなくても、「プログラムの入り口」が定義されていない、あるいはリンカに伝わっていないことが原因です。

原因1:main関数の記述ミスや欠如

最も単純で頻繁に発生する原因は、プログラム内にmain関数が正しく記述されていないケースです。

スペルミスと大文字・小文字の区別

C言語はアルファベットの大文字と小文字を厳格に区別するため、MainMAINと記述すると別の関数として扱われます。

また、mianのように単純なタイピングミスをしている場合も、リンカはmain関数が存在しないと判断します。

以下のコードは、典型的なスペルミスの例です。

C言語
#include <stdio.h>

// mainではなくmianとタイピングミスしている例
int mian(void) {
    printf("Hello, World!\n");
    return 0;
}

このコードをコンパイルしようとすると、以下のエラーが発生します。

実行結果
/usr/bin/ld: /usr/lib/gcc/x86_64-linux-gnu/11/../../../x86_64-linux-gnu/Scrt1.o: in function `_start':
(.text+0x1b): undefined reference to `main'
collect2: error: ld returned 1 exit status

関数のシグネチャが異なる場合

標準的なC言語では、main関数の戻り値は必ずint型でなければなりません。

古い開発環境や特定の組み込み環境を除き、戻り値をvoidに設定していると、環境によってはエントリーポイントとして正しく認識されないことがあります。

常に標準に準拠した形式で記述することを強く推奨します。

原因2:複数ファイルのリンク漏れ

中規模以上の開発プロジェクトでは、ソースコードを複数のファイルに分割して管理することが一般的です。

この際、main関数を含んでいるファイルをコンパイル対象に含め忘れると、このエラーが発生します。

分割コンパイル時のコマンド指定ミス

例えば、util.cmain.cの2つのファイルがあるプロジェクトを想定します。

もしコマンドラインでutil.cのみを指定してコンパイルを実行すると、リンカはmain関数を見つけることができません。

Shell
# エラーが発生するコマンドの例
gcc -o my_program util.c

この問題を解決するには、以下のようにすべての依存ファイルを列挙する必要があります。

Shell
# 正しいコマンド
gcc -o my_program main.c util.c

オブジェクトファイルからのリンク

大規模なプロジェクトでは、一度オブジェクトファイル(.oや.obj)を作成してからリンクを行うことが一般的です。

その際も、main.oをリンクの引数に含めることを忘れないように注意してください。

原因3:プロジェクト設定やビルドツールの不整合

統合開発環境(IDE)やビルドツール(Make、CMake、VSCodeなど)を使用している場合、設定ファイルの不備が原因となることが多いです。

VSCode(Visual Studio Code)での設定ミス

VSCodeでtasks.jsonを使用してビルドを行っている場合、argsプロパティに現在のファイル(${file})しか指定されていないことがあります。

これにより、別のファイルにあるmain関数が読み込まれず、エラーが発生するパターンが目立ちます。

プロジェクト内の全Cファイルを対象にするには、ワイルドカードを使用するなどの修正が必要です。

Windowsアプリケーションにおけるサブシステムの設定

Windows環境(Visual Studioなど)で開発している場合、「サブシステム」の設定が影響することがあります。

コンソールアプリケーションとして設定されている場合はmainが必要ですが、Windowsアプリケーション(GUI)として設定されている場合はWinMainが求められます。

プロジェクトのプロパティから「リンカー」→「システム」→「サブシステム」を確認し、意図した種類(コンソール)になっているかチェックしてください。

原因4:C++との混在による名前マングリング

C++プロジェクトの中にC言語のファイルを混ぜる場合、あるいはその逆の場合に発生する特殊なケースです。

C++コンパイラは、関数のオーバーロードをサポートするために、関数名を内部的に書き換える「名前マングリング(Name Mangling)」を行います。

もしmain関数がC++としてコンパイルされ、他の部分がC言語としてリンクを試みると、名前の不一致が生じることがあります。

これを防ぐためには、以下のようにextern "C"を使用して、C言語のリンケージを指定する必要があります。

C++
#ifdef __cplusplus
extern "C" {
#endif

int main(void) {
    // 処理
    return 0;
}

#ifdef __cplusplus
}
#endif

トラブルシューティングのためのチェックリスト

エラーが解決しない場合は、以下の表を参考に現在の状況を整理してみてください。

チェック項目確認内容解決策
スペル「main」が「mian」などになっていないか小文字で「main」と正しく記述する
ファイル保存ソースコードは保存されているかファイルを保存してから再コンパイルする
コンパイル対象main関数のあるファイルがコマンドに含まれているかgccの引数に全ソースファイルを含める
ビルドタイプライブラリとしてビルドしていないか実行ファイル形式(-cオプションなし)でリンクする

特に、「-c」オプションを付けたままリンクしようとしていないかは重要な確認ポイントです。

-cオプションはオブジェクトファイルを作成するだけでリンクを行わないため、最終的な実行ファイルを作るコマンドでは外す必要があります。

まとめ

「undefined reference to ‘main’」は、プログラムの開始地点が見つからないというリンカからの最終通告です。

その多くは、単純なタイピングミスや、複数ファイル構成におけるコンパイル対象の指定漏れといった初歩的なミスに起因しています。

まずは記述内容を再確認し、次にビルドコマンドやIDEの設定を見直すことで、ほとんどのケースは迅速に解決できます。

エラーメッセージは一見難解に見えますが、リンカの役割を理解していれば、原因を特定するための大きなヒントになります。

本記事で紹介した解決策を一つずつ試して、スムーズな開発環境を取り戻してください。