C言語基礎|列挙体の使い方

「数字のまま選ぶの、もう卒業!列挙体で“意味のある値”を気持ちよく扱おう」

列挙体は“少数の選択肢”を安全に表すための道具

C言語では、状態や選択肢を数字で表すことがよくあります。
でも、0 や 1 や 2 だけだと「それが何を意味する数字なのか」がコードから読み取りにくいですよね。

そこで便利なのが 列挙体(enum) です。

  • 扱える値が「限られた集合」になる(選択肢が明確)
  • 値に名前が付く(読めば意味が分かる)
  • switch と相性がよく、分岐がすっきりする

このページでは、元の「犬・猫・猿」ではなく、もっとシンプルに 天気(晴れ・くもり・雨・終了) を選んで表示する例に置き換えて、列挙体の使い方を表と図で丁寧に説明します。
人物は出さず、最後に図解イラスト用プロンプトも1つだけ付けますね。

列挙体(enum)とは何か

列挙体は「いくつかの決まった値だけを使う」ための型を作る仕組みです。

列挙体で向いているもの

値の候補が少ない?数字だけだと分かりにくい?列挙体が向く
曜日はいはい
メニュー選択はいはい
ON/OFFはいまあまあ
身長や点数いいえ(範囲が広い)数字そのものが意味

表の説明
「選択肢が少ない」「意味を名前で持たせたい」場合に列挙体がピッタリです。

サンプルプログラム

例:天気を選んでメッセージを表示する

プロジェクト名:chap8-6-1 ソースファイル名:chap8-6-1.c

Visual Studio でこのプログラムを実行するには、SDLチェック設定を変更しておく必要があります。
1.プロジェクト名を右クリックして、「プロパティ」をクリックします。
2.「C/C++」→「全般」→「SDLチェック」を「いいえ」に切り替えて「OK」をクリックします。

#include <stdio.h>

enum weather { Sunny, Cloudy, Rainy, Quit };

//--- 天気を選ぶ ---//
enum weather select_weather(void)
{
    int tmp;

    do {
        printf("0…晴れ  1…くもり  2…雨  3…終了:");
        scanf("%d", &tmp);
    } while (tmp < Sunny || tmp > Quit);

    return (enum weather)tmp;
}

//--- 天気メッセージを表示 ---//
void show_message(enum weather w)
{
    switch (w) {
    case Sunny:
        puts("日差しが気持ちいいですね。");
        break;
    case Cloudy:
        puts("のんびり過ごすのにちょうど良さそうです。");
        break;
    case Rainy:
        puts("傘を忘れずに行きましょう。");
        break;
    default:
        break;
    }
}

int main(void)
{
    enum weather selected;

    do {
        selected = select_weather();
        if (selected != Quit)
            show_message(selected);
    } while (selected != Quit);

    return 0;
}

実行例

0…晴れ  1…くもり  2…雨  3…終了:2
傘を忘れずに行きましょう。
0…晴れ  1…くもり  2…雨  3…終了:0
日差しが気持ちいいですね。
0…晴れ  1…くもり  2…雨  3…終了:3

列挙体タグと列挙定数

列挙体の宣言はこうです。

enum weather { Sunny, Cloudy, Rainy, Quit };

図:enum の構造(イメージ)

図の説明

  • weather が列挙体タグ(enum の名前のようなもの)
  • { ... } の中の Sunny などが列挙定数(選択肢の名前)
  • 何も指定しない場合、先頭から 0, 1, 2… と整数値が自動で割り当てられます

列挙型の変数宣言は、int と同じ形

列挙体で作られる型は、enum weather 型 のように enum を付けて呼びます。

変数宣言の形(比較)

int x;
enum weather selected;

説明
どちらも「型名 変数名;」という書き方です。
列挙型でも、宣言の形は普通の変数と同じなので、ここで迷いにくいのが良いところです。

なぜ列挙体を使うと読みやすい?

例えば selected == 2 だと、2 が何なのか毎回思い出す必要があります。
でも selected == Rainy なら、読むだけで意味が分かります。

数字だけ vs 列挙体

書き方読みやすさ意味の伝わり方
if (selected == 2)低い2 の意味が不明
if (selected == Rainy)高い雨だと一目で分かる

select_weather 関数のポイント:入力チェックが書きやすい

入力チェックはこの部分です。

tmp < Sunny || tmp > Quit

do-while で範囲をチェックする理由

項目内容
do-while を使う理由1回は必ず表示して入力させたい
範囲チェックの狙い0〜3 以外の入力を受け付けない
Sunny と Quit を使う利点数字を直書きしないので分かりやすい

表の説明
0〜3 と数字を直書きするより、Sunny や Quit を使うほうが「宣言と連動」して見通しが良くなります。

最後の列挙定数を Quit にするメリット(拡張に強い)

今回、最後を Quit にしました。これは「終了」用途でも便利ですが、範囲の上限にも使えます。

例えば将来、選択肢を増やしたくなったら…

選択肢を追加してもチェック式を変えにくくする方針

enum weather { Sunny, Cloudy, Rainy, Snowy, Quit };

tmp < Sunny || tmp > Quit

説明
新しい Snowy を追加しても、上限が Quit なのでチェック式をそのまま使えます。
「最後は Quit(または Invalid)」という設計は、拡張に強い定番テクニックです。

列挙定数の型はどうなっている?

Cでは、列挙定数(Sunny など)は実体として整数値です。
そのため、int tmp を enum weather として返すことができますが、あいまいさを減らすためにキャストしています。

return (enum weather)tmp;

キャストを書く理由

書き方意味おすすめ度
return tmp;int をそのまま返す
return (enum weather)tmp;enum weather として返す意図を明確化

switch との相性が最高な理由

列挙体は switch と組み合わせると、分岐がすごく読みやすくなります。

switch が向く理由

理由内容
case が選択肢の一覧になるSunny/Cloudy/Rainy が並び、見通しが良い
追加・変更が簡単列挙定数を追加したら case を足すだけ
if の連鎖より読みやすい条件がシンプルに整理される

登場する命令・構文の書式と役割まとめ

enum の書式

enum タグ名 { 列挙定数1, 列挙定数2, ... };

何をする?
限られた選択肢を名前付きの値として定義します。

変数宣言の書式

enum タグ名 変数名;

何をする?
列挙型の変数を作ります(取れる値が選択肢に限定されるイメージ)。

switch の書式

switch (式) {
case 値:
    文;
    break;
default:
    文;
}

何をする?
式の値に応じて処理を分岐します。列挙定数を case に書くと読みやすくなります。

do-while の書式

do {
    文;
} while (条件);

何をする?
最低1回は必ず繰り返します。入力を受け付ける処理でよく使います。

printf / scanf / puts の書式

  • printf:表示(書式付き)
  • scanf:入力(変数のアドレスへ格納)
  • puts:文字列を表示して改行

まとめ:列挙体を使うコツ

  • 値の候補が少ないなら、列挙体で名前を付けると読みやすい。
  • 入力チェックの上限・下限に列挙定数を使うと保守しやすい。
  • switch と組み合わせると選択肢が整理されて気持ちいい。
  • 最後に Quit / Invalid を置く設計は拡張に強い。