コンパイル前に実行される「前処理」の仕組みを学ぶ。
試験では #define のマクロ展開と演算子の優先順位を絡めた問題が頻出。
C言語のソースファイルは コンパイルの前 に「プリプロセッサ」という処理が実行される。
#(シャープ)で始まる命令がその対象。
| 命令 | 役割 |
|---|---|
#include | 外部ファイルを読み込む(stdio.h など) |
#define | マクロ定義(文字・式の置換) |
#ifdef / #endif | 条件によってコンパイルを分岐(3級範囲外) |
#define による置換は実行時ではなくソースコードの文字列置換として行われる。
#define 識別名 置換内容
識別名をソースコード中で使うと、コンパイル前に置換内容に書き換えられる。
#include <stdio.h>
#define PI 3.14
#define SIZE 5
int main(void)
{
printf("PI = %f\n", PI); /* → printf("PI = %f\n", 3.14); */
printf("SIZE = %d\n", SIZE); /* → printf("SIZE = %d\n", 5); */
return 0;
}
PI = 3.140000 SIZE = 5
#define の末尾にセミコロンは付けない。#define PI 3.14; と書くと PI が 3.14; に置換されてコンパイルエラーになる。
#include <stdio.h>
#define NAME "Taro"
int main(void)
{
printf("%s\n", NAME); /* → "Taro" が表示される(置換される)*/
printf("%s\n", "NAME"); /* → "NAME" と表示される(置換されない)*/
return 0;
}
Taro NAME
#define マクロ名(引数) 置換内容
#include <stdio.h>
#define SQUARE(x) ((x) * (x))
int main(void)
{
printf("%d\n", SQUARE(3)); /* → ((3) * (3)) = 9 */
printf("%d\n", SQUARE(1 + 2)); /* → ((1+2) * (1+2)) = 9 */
return 0;
}
9 9
#define BAD_SQUARE(x) x * x
#define GOOD_SQUARE(x) ((x) * (x))
int b = BAD_SQUARE(1 + 2); /* → 1 + 2 * 1 + 2 = 5(誤動作)*/
int c = GOOD_SQUARE(1 + 2); /* → ((1+2) * (1+2)) = 9(正動作)*/
() で囲む。演算子の優先順位による意図しない展開を防ぐため。
#define ADD x + y /* カッコなし */
int x = 2, y = 3;
int result = ADD * 2; /* → x + y * 2 = 2 + 6 = 8(意図は 5*2=10 だったかも)*/
#define ADD (x + y) /* カッコあり */
int result = ADD * 2; /* → (x + y) * 2 = 5 * 2 = 10 */
Q1. 次のコードで変数 a の値はどれか。
#define PI 3.14
float a = PI * 2;
正解:ア(6.28)
PI が 3.14 に置換され 3.14 * 2 = 6.28。
Q2. 次のコードで result の値はどれか。
#define ADD x + y
int x = 2, y = 3;
int result = ADD * 2;
正解:イ(8)
ADD * 2 → x + y * 2 → 2 + 3 * 2 = 2 + 6 = 8。* が + より優先される。
Q3. 次のコードで msg に格納される文字列はどれか。
#define NAME "Taro"
char msg[] = "NAME";
正解:ウ(NAME)
"NAME" は文字列リテラルなのでマクロ展開されない。
Q4. 次のコードで a, b の値の組み合わせとして正しいものはどれか。
#define MUL1 x + y * z
#define MUL2 (x + y) * z
int x = 1, y = 2, z = 3;
int a = MUL1;
int b = MUL2;
正解:ア(a=7, b=9)
MUL1 → 1 + 2 * 3 = 1 + 6 = 7
MUL2 → (1 + 2) * 3 = 3 * 3 = 9
Q5. 次のコードで TEXT を使って正しく展開されるのはどれか。
#define TEXT "Hello"
char a[] = TEXT;
char b[] = "TEXT";
正解:ア
TEXT は "Hello" に置換される。"TEXT" は文字列リテラルなので置換されず "TEXT" のまま。