Menu

C言語の構文:Cプログラムの構造を解説

どの C プログラムも同じ骨組みを持っています。インクルード、main 関数、セミコロンで終わる文、そして波かっこで囲まれたブロックです。それぞれの役割と、コンパイラが実際に強制する規則を見ていきます。

このページのコードはエディタで実行できます - 編集してすぐに結果を確認できます。

C言語に覚えるべき構文はごくわずかです。キーワードが約 32 個と、ひとにぎりの記号の規則だけ。あなたがこれから書くほとんどすべてのプログラムは同じ外形をしているので、その形を一度ていねいに分解しておく価値があります。

完全な最小のプログラム

これはコンパイルでき、実行でき、何もしません:

インクルードも、出力も、定型のクラスやモジュールもありません。main はエントリポイントです。オペレーティングシステムがあなたのプログラムを起動すると、main を呼び出します。main が返るとプログラムは終わり、返した値が終了ステータスになります。

出力を加えるなら、インクルードが 1 つ必要です:

プリプロセッサ指令

# で始まる行は、本来のコンパイルより前にプリプロセッサが処理します。これらは C言語の文ではなく、セミコロンは付けません

#include <stdio.h>    /* 標準ライブラリのヘッダー - 山かっこ */
#include "myutils.h"  /* 自作のヘッダー - 引用符、まず手元から探される */
#define MAX 100       /* マクロ - これ以降 MAX は 100 に置き換えられる */

#include は文字どおりのテキスト貼り付けです。指定したファイルの中身がまるごとその場所に落とし込まれます。stdio.h には printf の宣言が入っており、コンパイラはそれによって printf がどんな引数を取るかを知ります。インクルードを省くと implicit declaration of function 'printf' と言われます。

山かっこと引用符の違いは、コンパイラがどこを探すかの違いです。<...> はシステムのインクルードディレクトリを、"..." はまずこのファイルの隣を探すことを意味します。

main 関数

int main(void) {
    return 0;
}

4 つの部分があり、それぞれに意味があります:

  • int - main の戻り値の型。この値は終了ステータスとしてオペレーティングシステムに渡され、0 は成功を意味します。
  • main - ランタイムが呼び出す予約された名前。ホスト環境のCプログラムには必ず 1 つだけ存在します。
  • (void) - 引数リスト。ここでの void は「引数を取らない」という意味です。代わりに main() と書いても構文的には正しいのですが、弱くなります。C言語で空の括弧は「引数が未指定」を意味し、引数チェックが無効になるからです。
  • { ... } - 関数の本体。

もう 1 つの標準的な形はコマンドライン引数を取ります:

int main(int argc, char *argv[]) { ... }

必要になるまでは int main(void) を使いましょう。

文とセミコロン

とは 1 つの命令であり、セミコロンで終わります。

文が 4 つ、セミコロンが 4 つです。セミコロンは区切り記号ではなく終端記号なので、ブロックの最後の文にも必要です。

セミコロンを付けないもの:

#include <stdio.h>        /* プリプロセッサの行 - セミコロンなし */

int add(int a, int b) {   /* 関数定義のヘッダー - セミコロンなし */
    return a + b;
}                         /* 関数の閉じ波かっこ - セミコロンなし */

if (x > 0) {
    ...
}                         /* 制御ブロックの閉じ波かっこ - セミコロンなし */

誰もがやられるのは、本体があるべき場所のセミコロンです:

if (score > 90);              /* BUG: this ; is the entire if body */
    printf("Excellent!\n");   /* always runs, whatever score is */

これは完全に正しい C言語です。if は空文を制御しており、printf はただ順番に続く次の行にすぎません。-Wall は警告してくれますが、コンパイラが止めてくれることはありません。

ブロックと波かっこ

波かっこは複数の文をまとめてブロックにします。ブロックは、文が期待される場所ならどこでも 1 つの文として扱われます。

本体が 1 文だけなら波かっこは省略できますが、省略こそがあの有名なバグの生まれ方です。あとから 2 行目を足すと、それは静かに if の外に出てしまいます。波かっこは常に使いましょう。

ブロックはスコープも作ります。{ ... } の中で宣言した変数は、閉じ波かっこで存在しなくなります。

大文字小文字の区別と空白

C言語はどこでも大文字と小文字を区別しますtotalTotalTOTAL は 3 つの別々の名前です。キーワードはすべて小文字なので、IntReturnPrintf はいずれもエラーになります。しかも Printf のエラーメッセージは分かりにくいものになります。コンパイラは、聞いたこともない何かの関数のつもりなのだろうと解釈するからです。

一方、空白はほとんど自由です。コンパイラは、連続するスペース・タブ・改行をひとつの区切りとして扱います。これは正しいコードです:

int    main ( void )
{
    printf
    ( "Hello\n" ) ;
    return 0 ;
}

これもです:

int main(void){printf("Hello\n");return 0;}

どちらもまったく同じようにコンパイルされます。コンパイラが気にしない以上、書式は完全に人間のためのものです。慣習的なレイアウト(1 行に 1 文、ネスト 1 段につきスペース 4 つかタブ 1 つ、開き波かっこは同じ行)に従う価値はあります。あなたが読むことになる C言語のコードは、どれもそれに近いものを使っているからです。

空白が本当に問題になる場所が 2 つあります。キーワードや識別子を分割することはできません(in tint ではありません)。そして、普通の文字列リテラルの中に改行を入れることもできません。

識別子:命名の規則

識別子とは、あなたが選ぶ名前すべて、つまり変数・関数・型の名前です。規則は次のとおりです:

  • 英字、数字、アンダースコアで構成する。
  • 数字で始めてはいけないtotal2 はよいが 2total はだめ。
  • キーワードは使えない。intforreturn という名前の変数は作れません。
  • 大文字小文字は区別される。
  • アンダースコアで始まる名前、およびアンダースコアが 2 つ続くものは処理系用に予約されています。自分で作らないでください。
int score;        /* good */
int total_items;  /* good - snake_case is the C convention */
int _hidden;      /* legal but reserved - avoid */
int 2fast;        /* error */
int float;        /* error - keyword */

すべてに注釈を付けたプログラム

ここまでの内容を 1 か所にまとめます:

ここでは読む順序が重要です。with_taxmain が使うよりに定義されています。C言語はファイルを上から下へ読むので、関数は呼ばれる前に宣言されていなければなりません。先に定義するか、先頭に関数プロトタイプを書いてあとから定義しましょう。

よくある質問

C プログラムの基本的な構造は?

まずプリプロセッサ指令(#include <stdio.h>)、次に関数定義が続き、そのうち 1 つは main でなければなりません。関数の中では文がセミコロンで終わり、ブロックは波かっこで囲みます。最小のプログラムは #include <stdio.h>int main(void) { return 0; } を加えたものです。

なぜ main() ではなく int main(void) なのですか?

int は main の戻り値の型で、プログラムがオペレーティングシステムに返す終了ステータスです。(void) は main が引数を取らないことを明示します。括弧を空にして main() と書くのは古いスタイルで、引数について何も伝えないため、コンパイラのチェックが弱くなります。

C言語のすべての文にセミコロンは必要ですか?

すべてのには必要ですが、すべての行に必要なわけではありません。プリプロセッサ指令(#include#define)、関数定義、ブロックや ifforwhile の閉じ波かっこには付けません。if (x) の直後の余計なセミコロンは正しい C言語であり、本体を無条件に実行させてしまいます。

C言語は大文字と小文字を区別しますか?

はい、完全に区別します。countCountCOUNT は 3 つの別々の識別子で、Int はキーワード int ではありません。C言語のキーワードはすべて小文字なので、ReturnPrintf のように大文字を入れるとエラーになります。

Coddy programming languages illustration

Coddyでコードを学ぼう

始める