本文へスキップ
BecomeCoder

C言語コース · 第9章 プリプロセッサ · レッスン36

#define ― 定数とマクロ関数

ブラウザで完結

導入

同じ数値(たとえば消費税率や配列のサイズ)をコードのあちこちに直接書いていると、後で変更するときに1か所でも直し忘れて不具合が起きます。#define を使えば、その値に名前を付けて一元管理できます。

説明

#define 名前 値 と書くと、以降のコードに出てくる 名前 が、コンパイルされる前に文字どおりその に置き換えられます。関数のように呼び出せる「関数マクロ」も作れます。

#include <stdio.h>

#define PI 3.14
#define SQUARE(x) ((x) * (x))

int main(void) {
    printf("円周率は %f\n", PI);
    printf("5の2乗は %d\n", SQUARE(5));
    return 0;
}

PI は単純に 3.14 という文字列に置き換わるだけです。SQUARE(x) は「引数を受け取る」ように見えますが、これもプリプロセッサによる文字の貼り替えにすぎません。SQUARE(5)((5) * (5)) にそのまま置き換わります。

flowchart LR
  src["ソースコード<br/>SQUARE(5)"] -->|"プリプロセッサが文字を置換"| exp["((5) * (5))"]
  exp -->|"この形でコンパイル"| bin["実行ファイル"]

ここで注目してほしいのが SQUARE(x) の定義に付いている括弧の多さです。(x) と、全体を囲む ( ) の両方が必要です。理由は「ただの文字の貼り替え」だから起こる事故を防ぐためです。次のように括弧を省略すると、思わぬ結果になります。

#include <stdio.h>

#define BAD_SQUARE(x) x * x

int main(void) {
    printf("%d\n", BAD_SQUARE(2 + 3));  // 期待は25だが…
    return 0;
}

BAD_SQUARE(2 + 3)2 + 3 * 2 + 3 に置き換わります。掛け算は足し算より先に計算されるので、2 + 6 + 3 = 11 という、意図しない値になってしまいます。SQUARE(x) のように (x) と全体を ( ) で囲んでいれば、((2 + 3) * (2 + 3)) となり、正しく 25 になります。マクロの引数と全体は必ず括弧で囲む、という習慣を付けましょう。

やってみよう

SQUARE(5)SQUARE(2 + 3) に変えて 25 になることを確かめましょう。BAD_SQUARE の例も実行して、括弧を省略した場合の結果と比べてみてください。

演習

値を2倍にするマクロ DOUBLE(x) を、括弧を正しく使って定義してください。int n = 7; に対して DOUBLE(n)printf で表示してください(結果は 14)。

ヒント1を見る

マクロ定義は #define DOUBLE(x) ((x) * 2) のように書きます。

ヒント2を見る

呼び出しは普通の関数のように DOUBLE(n) と書けます。

実際に動かしてみよう

下のエディタにCを書いて「実行」を押すと、ブラウザ内のインタプリタで出力が表示されます。本文の例をそのまま試したり、書き換えたりしてみましょう(scanf を使う回は「標準入力」欄に値を入れてから実行します)。

C/C++ — ブラウザ内で実行

ブラウザ内でC/C++を動かす学習用インタプリタ(JSCPP)を読み込みます(入門向けのサブセットです)。
スクロールして表示された時点でも自動で読み込まれます。