
C言語基礎|列挙体と名前空間
「enum は“定数の集まり”以上!ミスを減らし、名前の衝突も整理できる賢い道具」
列挙体と名前空間を知ると、Cのコードがグッと安全になる。
列挙体(enum)は、単に「0,1,2…に名前を付ける」だけじゃありません。
実は、次のような“うれしい特徴”がいくつもあります。
- マクロで定義するより短く書ける(ミスも減る)
- 不正な値を代入したとき、コンパイラが警告してくれることがある。
- デバッガで値が数字ではなく名前で見えることがある。
- さらに、列挙体タグと変数名は別の名前空間なので、同じ綴りでも区別できる。
この記事では、月の例を「曜日」に置き換えたシンプルなプログラムを使って、
enum とマクロの違い、型としての良さ、デバッグの助け、そして「名前空間」まで、表と図でしっかり解説しますね。

enum とマクロの違い:定義の短さとミスの減り方
「1〜7の曜日」を表したいとします。マクロでやるとこうなりがちです。
マクロで曜日を作ると
#define MONDAY 1
#define TUESDAY 2
#define WEDNESDAY 3
#define THURSDAY 4
#define FRIDAY 5
#define SATURDAY 6
#define SUNDAY 7
図の説明
行数が増える上に、全部の値を手で書くので、うっかりミス(例えば FRIDAY を 6 にしてしまう等)が起きやすいです。
一方、enum ならこう書けます。
enum で曜日を作る
enum weekday { MONDAY = 1, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY };
説明
最初の MONDAY = 1 だけ正しく書けば、残りは「直前 + 1」で自動的に続きます。
値の手入力が減るので、ミスも減りやすいんです。
マクロと enum の比較
| 観点 | マクロ | enum |
|---|---|---|
| 記述量 | 多くなりがち | まとまって短い |
| 値の管理 | 全部手で指定しがち | 先頭だけ指定→自動で増える |
| 型の情報 | 型ではない(ただの置換) | 列挙型という型になる |
| デバッガ表示 | 数字のままになりがち | 名前で見えることがある |
表の説明
enum は「値のセット」だけでなく「型」も作るのが強みです。ここが次の話につながります。
列挙型は“型”なので、不正な値に気づきやすい
例えば、enum animal が 0〜3 の範囲を表すとして、そこに 5 を入れるコードを書いたらどうなるでしょう。
不正値代入のイメージ
enum animal an;
an = 5; // 変な値
説明
C言語は厳密に実行時チェックをしてくれるわけではありませんが、
コンパイラによっては「列挙型に範囲外っぽい値を入れてるよ」と警告を出してくれることがあります。
int だと“ただの数字”なので、こういうヒントが出にくいんですね。
int だけで書く場合との違い
| 書き方 | 間違いに気づきやすい? | 理由 |
|---|---|---|
| int x; x = 5; | 低い | 5 が正しいか判断できない |
| enum animal an; an = 5; | 上がる場合がある | enum の意図から外れていると警告が出ることがある |
表の説明
列挙型は“表したい集合が決まっている”という意図をコードに埋め込めるのが強いです。
デバッグが楽になる:数字ではなく名前で見えることがある
デバッガによっては、列挙型の値を数字ではなく列挙定数名で表示してくれます。
デバッガ表示のイメージ
selected = 0 → Dog
selected = 1 → Cat
図の説明
0 や 1 を見て意味を思い出す手間が減ります。
状態が多いプログラムほど、これが地味に効きます。
重要:enum で表せそうな集合は enum にしよう
ここまでの話をまとめると、次の方針がかなりおすすめです。
enum が向く集合
| 集合の種類 | enum にすると良い? | 例 |
|---|---|---|
| 少数の選択肢 | ◎ | 曜日、月、季節、メニュー |
| 状態の種類 | ◎ | 初期化中、実行中、終了 |
| エラー種別 | ○ | OK, NG, TIMEOUT |
| 大きい数値範囲 | △ | 点数、身長、温度 |
名前空間:列挙体タグ名と変数名は別の世界
ここからが「名前空間(name space)」の話です。
C言語では、識別子(名前)が全部同じ箱に入っているわけではなく、種類によって“別の箱”に分かれています。
そのため、列挙体タグと変数名は別の名前空間に属します。
結果として、同じ綴りでも区別できます。
同じ綴りでもOKな例
enum animal animal;
説明
- 最初の animal は「列挙体タグ」
- 後ろの animal は「変数名」
同じ綴りでも、種類が違うので衝突しません。
Cでよく意識する名前空間(ざっくり)
| 種類 | 例 | 備考 |
|---|---|---|
| 列挙体タグ | enum animal の animal | 変数名とは別 |
| 変数名 | int animal; の animal | タグ名とは別 |
| 関数名 | int select(void); の select | 変数名と同じ空間になりやすい |
| 列挙定数 | Dog, Cat など | 変数名と衝突しうるので注意 |
表の説明
ここがちょっとややこしいポイントです。
タグ名と変数名は別でも、列挙定数(Dogなど)は“普通の名前”として使われるので、変数名とぶつかる可能性があります。
そのため、列挙定数には ANIMAL_DOG みたいに接頭辞を付ける流儀もよく使われます。
サンプルプログラム
「列挙体の便利さ」と「名前空間で同名が使える」を一度に見られる、小さな例です。
テーマは「状態(mode)で表示メッセージを変える」です。
プロジェクト名:chap8-8-1 ソースファイル名:chap8-8-1.c
Visual Studio でこのプログラムを実行するには、SDLチェック設定を変更しておく必要があります。
1.プロジェクト名を右クリックして、「プロパティ」をクリックします。
2.「C/C++」→「全般」→「SDLチェック」を「いいえ」に切り替えて「OK」をクリックします。
#include <stdio.h>
enum mode { MODE_STOP, MODE_RUN, MODE_QUIT };
int main(void)
{
enum mode mode; // enum タグと同名でもOK(ここではタグ名は mode ではないので参考例)
int n;
do {
printf("0…停止 1…実行 2…終了:");
scanf("%d", &n);
mode = (enum mode)n;
switch (mode) {
case MODE_STOP:
puts("いったん停止します。");
break;
case MODE_RUN:
puts("処理を開始します。");
break;
case MODE_QUIT:
puts("終了します。おつかれさまでした。");
break;
default:
puts("0〜2で入力してください。");
break;
}
} while (mode != MODE_QUIT);
return 0;
}実行例
0…停止 1…実行 2…終了:1
処理を開始します。
0…停止 1…実行 2…終了:2
終了します。おつかれさまでした。登場する命令・構文の書式と役割
enum の書式
enum タグ名 { 列挙定数, 列挙定数, ... };
何をする?
限られた値の集合を、名前付きで定義し、列挙型(enum タグ名 型)を作ります。
変数宣言の書式
enum タグ名 変数名;
何をする?
列挙型の変数を作ります。状態や選択肢の変数に向きます。
switch の書式
switch (式) {
case 値:
文;
break;
default:
文;
}
何をする?
式の値で分岐します。列挙定数を case に書くと、意味が読みやすくなります。
printf / scanf / puts の書式
- printf
printf("書式文字列", 値, ...); 画面表示。 - scanf
scanf("書式文字列", 変数のアドレス, ...); 入力を読み取って変数へ格納。 - puts
puts("文字列"); 文字列を表示して改行。
まとめ:enum を使うと「安全」「読みやすい」「管理しやすい」
- マクロより短く書けて、値の指定ミスも減らせる。
- 型として扱えるので、間違いに気づきやすくなる(警告やデバッグ表示の助け)
- 名前空間が分かれているので、タグ名と変数名は同じ綴りでも区別できる。
- 迷ったら「enum で表せる集合は enum にする」が安定です。
