閉じる

はじめてのC言語:#includeとmain関数を基礎から解説

C言語の最初の一歩は、プログラムの骨組みを理解することです。

特に#includemain関数は、すべてのCプログラムに共通する最重要要素です。

本記事では、ファイル構成と書き方の流れ#includeの基本main関数の役割、そしてよくあるエラーと対処を、初心者の方にも分かりやすく段階的に解説します。

C言語のプログラムの基本構造

ソースコードの骨格(#includeとmain関数)

Cプログラムは、必要な宣言や機能を読み込む#includeと、実行の起点であるmain関数で構成されます。

最小構成の例として、画面に文字を表示するプログラムを示します。

C言語hello.c
// hello.c
// C言語の最小構成例: #include と main 関数
#include <stdio.h>  // 標準入出力の関数(printf など)を使うために必要

int main(void) {    // プログラムのエントリポイント(開始地点)
    // 画面に文字を表示する
    printf("Hello, World!\n");
    return 0;       // 正常終了を表す(詳細な意味は別記事で解説)
}
実行結果
Hello, World!

この例では#include <stdio.h>で標準入出力の宣言を読み込み、main関数内でprintfを呼び出します

ヘッダを読まないと関数の宣言が分からず、警告やエラーの原因になるため、必ず冒頭で適切に#includeします。

ファイル構成(.cと.h)の基本

C言語では、処理の本体は拡張子.c、宣言は拡張子.hに分離するのが基本です。

自作関数を別ファイルに分ける例を示します。

C言語myutil.h
// myutil.h (ヘッダファイル)
// ここには「宣言」だけを書くのが基本です。
// 多重インクルード対策としてインクルードガードを入れます。
#ifndef MYUTIL_H
#define MYUTIL_H

int add(int a, int b);  // 関数の宣言(プロトタイプ宣言)

#endif // MYUTIL_H
C言語myutil.c
// myutil.c (実装ファイル)
// ここには関数の「定義(本体)」を書きます。
#include "myutil.h"  // 自作ヘッダは二重引用符で
int add(int a, int b) {
    return a + b;
}
C言語main.c
// main.c
#include <stdio.h>
#include "myutil.h"  // 自作の宣言を読み込む

int main(void) {
    int result = add(12, 30);  // 別ファイルの関数を利用
    printf("12 + 30 = %d\n", result);
    return 0;
}
実行結果
12 + 30 = 42

この構成により、複数の.cから同じヘッダ.hを共有でき、再利用性と可読性が向上します。

ビルド時は全ての.cを一緒にコンパイル・リンクします(例:gccならgcc main.c myutil.c -o app)。

実行の流れ(エントリポイントはmain関数)

OSはプログラム起動時にmain関数を呼び出すため、実行は必ずmainから開始されます。

mainの内部で他の関数が順次呼ばれ、最終的にreturnで終了ステータスを返してプロセスが終了します。

#includeの基礎

#includeとは(ヘッダファイルを読み込む仕組み)

#includeは、指定したヘッダファイルの内容をソース中にそのまま差し込む(テキスト展開する)プリプロセッサ命令です。

これにより、関数や型、マクロの宣言が現在のソースから参照できるようになります。

プリプロセッサと#includeの関係

コンパイル前にプリプロセッサ#includeを処理します。

具体的には、条件コンパイル#ifやマクロ#defineもこの段階で展開されます。

gccでは-Eオプションでプリプロセス結果を確認できます(学習時に差分を見ると理解が深まります)。

標準ヘッダと自作ヘッダの違い

標準ヘッダはコンパイラ/標準ライブラリに付属し、決められたインクルードパスから検索されます。

自作ヘッダはプロジェクト内のファイルで、相対パスまたはプロジェクト設定の検索パスから見つかります。

種別置き場所の例典型的な用途
標準ヘッダ<stdio.h>, <stdlib.h>システムやコンパイラ提供のディレクトリ標準関数の宣言
自作ヘッダ"myutil.h"プロジェクトのソースディレクトリ自作関数や型の宣言

山括弧(<> )と二重引用符(“”)の使い分け

標準ヘッダは#include <...>、自作ヘッダは#include "..."で書くのが原則です。

実装上、<...>はシステムディレクトリのみを検索し、"..."はまずカレントディレクトリ(またはソースのあるディレクトリ)を優先して検索します。

C言語
#include <stdio.h>   // 標準ヘッダ: 角括弧
#include "config.h"  // 自作ヘッダ: 二重引用符(まず現在のディレクトリを探索)

インクルードの順序と書き方のコツ

自分のヘッダを最初にインクルードし、続いて標準ヘッダや外部ライブラリのヘッダを読み込むと、自ヘッダの独立性(自己完結性)を検証できます。

もし自ヘッダで必要な他のヘッダが足りない場合、ここでコンパイルエラーになり、依存関係の漏れに早く気付けます。

加えて、不要な重複インクルードを避け#includeの並び順をプロジェクトで統一すると可読性が上がります。

多重インクルード対策(インクルードガード/pragma once)

同じヘッダを複数回#includeすると、再定義エラーの原因になります。

これを防ぐためにインクルードガードを使います。

C言語sample.h
// sample.h
#ifndef SAMPLE_H   // まだ定義されていなければ
#define SAMPLE_H   // これ以降を一度だけ有効化

typedef struct {
    int id;
} Item;

#endif // SAMPLE_H

一部のコンパイラでは#pragma onceも使えます。

C言語sample2.h
// sample2.h
#pragma once
void foo(void);

移植性重視ならインクルードガード、手軽さ重視なら#pragma onceという選択が一般的です。

main関数の役割と書き方

main関数の基本形(int main(void))

Cプログラムは必ずint main(void)または等価の形式で開始します。

最も基本的な形を再掲します。

C言語
// basic_main.c
#include <stdio.h>

int main(void) {           // 引数なし
    printf("Program start\n");
    return 0;              // 正常終了(詳細は別記事)
}
実行結果
出力例:
Program start

戻り値はOSに終了ステータスを返すために使われます。

非標準のvoid mainは避けましょう

コマンドライン引数付き(int argc, char* argv[])

コマンドラインから値を受け取る場合は、int main(int argc, char* argv[])を使います。

C言語
// args.c
#include <stdio.h>

int main(int argc, char* argv[]) {
    // argc は引数の個数、argv は各引数の文字列
    printf("argc = %d\n", argc);
    for (int i = 0; i < argc; ++i) {
        printf("argv[%d] = %s\n", i, argv[i]);
    }
    return 0;
}
実行結果
実行例(コマンド):
./args one two

出力例:
argc = 3
argv[0] = ./args
argv[1] = one
argv[2] = two

引数の0番目は実行ファイル名である点に注意してください。

プログラムはmainから始まる(エントリポイント)

OSのローダはプログラム起動時にmainを呼び出し、mainが返った時点でプロセスは終了します。

グローバル変数の初期化や静的初期化子はmainの前に評価されますが、通常の処理フローはmain内で記述します。

mainは1つだけ(複数定義のエラーに注意)

プロジェクト全体で定義できるmainは1つだけです。

複数の.cmainを置くとリンク時にエラーになります。

典型的にはmultiple definition of main(GCC系)やLNK2019(MSVC)が発生します。

main関数の配置と可読性のポイント

可読性の観点から、mainはファイルの先頭付近に置き、詳細処理は関数へ分割するのが推奨です。

関数プロトタイプ宣言をmainより前に置くか、適切なヘッダに宣言をまとめると、コンパイラが未宣言呼び出しを検出できます。

よくあるエラーと対処(#includeとmain関数)

‘stdio.h’が見つからない(インクルードパスの確認)

エラーメッセージ例: fatal error: stdio.h: No such file or directory

これはコンパイラが標準ヘッダの検索パスを見つけられない場合に起きます。

WindowsでMinGWやClangをインストールしていない、または環境変数PATH/インクルードパス設定が不完全な可能性があります。

まずはコンパイラの正しいインストールと、ビルドコマンドを再確認してください。

自作ヘッダなら#include "my.h"の相対パスが合っているか、-Iオプションで検索ディレクトリを追加しているかを確認します。

mainが見つからない/宣言が不正(シグネチャを見直す)

エラーメッセージ例: undefined reference to mainLNK2019: unresolved external symbol main

これはmain関数が定義されていない、または非標準のvoid mainや誤った引数で定義している可能性があります。

int main(void)int main(int,char*[])に修正しましょう。

C言語
// NG例: 非標準の main
void main() {               // ← 非推奨・非標準
    // ...
}

// OK例: 標準的な main
int main(void) {
    return 0;
}

閉じカッコやセミコロンの不足(構文エラー)

Cではセミコロンや波括弧の不足が頻繁なミスです。

エラーメッセージの行番号を手掛かりに、対応関係を確認しましょう。

C言語
// NG例: セミコロン抜け
#include <stdio.h>
int main(void) {
    int x = 10  // ← セミコロンがない
    printf("%d\n", x);
    return 0;
}

// OK例:
#include <stdio.h>
int main(void) {
    int x = 10; // ← セミコロンあり
    printf("%d\n", x);
    return 0;
}
実行結果
OK例の出力:
10

エディタの構文ハイライトや自動整形、インデントを活用すると、対応ミスに早く気付けます。

同名のmainを複数定義した(リンクエラー)

複数の.cmainがあると、リンク時に重複定義エラーになります。

サンプルやテスト用に複数のエントリポイントを用意する場合は、同時にビルドしないか、#ifdefで切り替えるなどの工夫が必要です。

C言語
// main_a.c
int main(void) { return 0; }

// main_b.c
int main(void) { return 0; }  // ← これと main_a.c を同時にリンクするとエラー

gcc main_a.c main_b.c -o appのように同時にリンクすると、GCC系ならmultiple definition of mainが出ます。

まとめ

C言語の基礎は#includeで宣言を整え、mainから処理を開始するという明快な構造にあります。

.cと.hの役割分担を守り、インクルードの書き方と順序、インクルードガードを徹底すれば、拡張しやすくエラーに強いコードになります。

最後に、mainは1つだけ、シグネチャは標準形、ヘッダは正しく探させるという3点を常に確認してください。

これらを押さえることで、以降の入出力やデータ型、変数操作といった学習を安定して進められます。

この記事を書いた人
エーテリア編集部
エーテリア編集部

プログラミングの基礎をしっかり学びたい方向けに、C言語の基本文法から解説しています。ポインタやメモリ管理も少しずつ理解できるよう工夫しています。

クラウドSSLサイトシールは安心の証です。

URLをコピーしました!