C言語のきほん|オブジェクト形式マクロの利用

数字を直書きしないだけで、コードは一気に読みやすくなる。オブジェクト形式マクロで“意味のある定数”を育てよう。

繰り返し回数を変えたいとき、数字を探し回るのはもう卒業

for文の回数や上限って、あとから変えたくなることが多いです。
でもコードのあちこちに 10 や 30 みたいな数字が散らばっていると、修正が面倒だし、変更漏れも起きやすいんですよね。

そこで役立つのが オブジェクト形式マクロ です。
回数や上限などの「意味のある定数」に名前を付けて、プログラム冒頭でまとめて管理できるようにします。

結果として、

  • 変更が1か所で済む
  • その数字の意味がコードから読み取れる
  • 修正ミスが減る

という、地味だけど強いメリットが得られます。

#defineとは(前処理で置き換える仕組み)

#define は 前処理指令 です。コンパイルの前に動いて、ソースコード中のマクロ名を置換文字列に置き換えます。

オブジェクト形式マクロと関数形式マクロ

種類役割
オブジェクト形式マクロ定数や文字列に名前を付ける#define LIMIT 10
関数形式マクロ関数っぽく引数を受け取って展開#define MAX(a,b) ...

今回は「定数に名前を付ける」オブジェクト形式マクロがテーマです。

オブジェクト形式マクロの文法

#define マクロ名 置換文字列
要素意味コツ
#define前処理指令行頭に書く
マクロ名置換される名前定数らしく大文字にすることが多い
置換文字列実際に置き換わる内容数値、文字列、式もOK

セミコロンを付けない(重要)

#define の行にセミコロンを付けると、そのセミコロンまで置換されます。
意図しない場所に ; が出てきて、変なエラーや動作になるので、付けないようにします。

まずは「直書き」と「マクロ化」を比べてみる

たとえば、繰り返し回数が 8 回だとします。

  • 直書き:forの条件に8が埋まる
  • マクロ:REPEAT という名前にして意味を見せる

読み手にとっては、REPEAT の方が「何の8?」が分かりやすいです。
数字そのものより、「意図」が大事なんですよね。

サンプルプログラム

例:回数をマクロで管理して、合図メッセージを繰り返す

  • TIMES を変えるだけで、表示回数がまとめて変わる
  • ついでに、別のforでも TIMES を使って “2倍回数” を表現する

ファイル名:9_6_1.c

// オブジェクト形式マクロで繰り返し回数をまとめて管理するプログラム
#include <stdio.h>

#define TIMES 4   // 繰り返し回数の基準

int main(void)
{
    // TIMES回だけメッセージを表示
    for (int i = 1; i <= TIMES; i++) {
        printf("チェック中… %d回目\n", i);
    }

    printf("-----\n");

    // TIMESの2倍回だけ別のメッセージを表示
    for (int i = 1; i <= (TIMES * 2); i++) {
        printf("ログ出力 %d回目\n", i);
    }

    return 0;
}

この例だと、TIMES を 4 から 6 に変えるだけで、

  • 上のループは 6 回
  • 下のループは 12 回

にまとめて変わります。数字を探して書き換える必要がありません。

マクロを使う利点(実務でも効くポイント)

変更が一か所で済む

回数や上限を変えるとき、マクロ定義の行だけを直せばOKになります。
ループが複数あっても一括で変更できるので、変更漏れが減ります。

コードの意味が読み取りやすい

TIMES や LIMIT のような名前があると、数字の役割が明確になります。

直書きマクロ化読みやすさ
i <= 30i <= MAX_COUNT意味が伝わる
i += 2 を30までi <= EVEN_LIMIT読む人が迷いにくい

保守性が上がる

数字を直書きすると、同じ数字が別の意味で使われていることがあります。
マクロで名前を付けると、意図が分離されて事故が減ります。

constとの使い分け(さらっと方向性だけ)

文書にもあった通り、オブジェクト形式マクロの代わりに const でも似たことができます。

  • マクロ:前処理で置換される
  • const:型を持つ定数として扱える

学習の流れとしては、「まずマクロで定数化に慣れる」→「constも使えるようにする」でOKです。

実践問題

テーマは「繰り返し回数や上限をマクロで指定する」です。

1から上限までの数を表示し、5個表示するごとに改行するプログラムを作成してください。
上限と改行の間隔はオブジェクト形式マクロで指定してください。

  • 上限:LIMIT
  • 改行間隔:BREAK_EVERY

実行イメージ(例:LIMITが20、BREAK_EVERYが5)

1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20

解答例

ファイル名:9_6_2.c

// マクロで上限と改行間隔を指定して数値を表示するプログラム
#include <stdio.h>

#define LIMIT 20
#define BREAK_EVERY 5

int main(void)
{
    for (int i = 1; i <= LIMIT; i++) {
        printf("%d ", i);

        // BREAK_EVERY個ごとに改行
        if (i % BREAK_EVERY == 0) {
            printf("\n");
        }
    }

    // きれいに終わるための改行(LIMITがBREAK_EVERYの倍数でない場合に備える)
    if (LIMIT % BREAK_EVERY != 0) {
        printf("\n");
    }

    return 0;
}

解説:マクロ化すると「意味がコードに残る」

このプログラムで大事なのは、数字の意味が名前になっているところです。

  • LIMIT が「どこまで表示するか」
  • BREAK_EVERY が「何個ごとに改行するか」

これが直書きで 20 や 5 になっていると、後から読んだ人は「なんで20?なんで5?」となりがちです。
マクロにすると、意図がそのまま残ります。

実践問題

正の整数値を入力し、次のルールで数列を表示してください。

  • 例:9 → 1 2 3 4 5 4 3 2 1
  • 例:10 → 1 2 3 4 5 5 4 3 2 1
  • 例:1 → 1

ヒント:中央の最大値は、入力を2で割った値あたりになります。

解答例

ファイル名:9_6_3.c

// 入力値に応じて山型の数字列を表示するプログラム
#include <stdio.h>int main(void)
{
    int n;    printf("正の整数値を入力してください > ");
    scanf("%d", &n);    if (n <= 0) {
        printf("エラー:1以上の整数を入力してください。\n");
        return 0;
    }    // 山の頂点(奇数なら中央1回、偶数なら中央2回になる)
    int peak = (n + 1) / 2;    // まず 1 から peak まで
    for (int i = 1; i <= peak; i++) {
        printf("%d ", i);
    }    // 偶数なら peak をもう一度出す(例:10 → ... 5 5 ...)
    if (n % 2 == 0) {
        printf("%d ", peak);
    }    // そして peak-1 から 1 まで戻る
    for (int i = peak - 1; i >= 1; i--) {
        printf("%d ", i);
    }    printf("\n");
    return 0;
}

解説

  • 入力nから頂点 peak を決める
    (n + 1) / 2 だと、9→5、10→5 になって便利
  • 前半で 1→peak
  • 偶数なら peak を追加でもう1回
  • 後半で peak-1→1

この分け方にすると、奇数・偶数の差が if (n % 2 == 0) の1か所に集まって、読みやすくなります。