プリプロセッサは、ソースコードをコンパイラーに渡す前に実行される前処理です。これはC言語の中でも非常に強力な機能で、使いこなすことでプログラミングの精度を高めたり、効率を上げたりすることができます。
ディレクティブを和訳すると「指示文」となります。コンパイラーなどに指示を与えることに使われます。皆さんが何気なく、そういうものだからと日常的に使用している「#include」もディレクティブの1つなのです。
#includeディレクティブ
その場に指定したファイルを読みだして挿入します。そんなincludeディレクティブには2つの形式があります。
- #include <systemfile.h>
- #include “myfile.h”
前者は標準ヘッダーファイルをインクルードするために使い、後者は開発者が自作したファイルをインクルードするために使います。
#defineディレクティブ
一般的にマクロと呼ばれているもので、コンパイル前に定義した値に置き換えます。これにより得られるメリットは様々です。意味のある定数に名前を与えることができ、かつ1個所修正するだけでソースコードの複数個所をまとめて編集できるのです。
#define CHAN_MAX (12)
void func(void)
{
int i;
for (i = 0; i < CHAN_MAX; i) { // コンパイル時に"12"に置き換えられる
...
}
}
また置き換えられるのは定数だけではありません。簡単なものなら関数を置き換えることも可能です。
#define MAX(a, b) ((a) > (b) ? (a) : (b))
void func(int x1, int x2)
{
int max;
max = MAX(x1, x2);
}
注意点
マクロは必ず括弧で囲ってください。上の例でいうと「(12)」や「(a)」、「((a) > (b) ? (a) : (b))」がそれです。これはマクロと関数の明確な違いで、マクロは文字列の置き換えでしかないということです。
関数形式のマクロは便利です。通常の関数と違い呼び出し時のオーバーヘッドもありません。しかし関数形式のマクロは通常の関数とは違います。使い方を誤ると思わぬ不具合を生む恐れもあります。たとえば先ほどのMAXの大外に括弧がなかった場合、次のようなことが起こります。
// #define MAX(a, b) (a) > (b) ? (a) : (b)
// max = MAX(2, 1) + 1;
max = (2) > (1) ? (2) : (1) + 1 // max = 2
この他にも関数形式マクロならではの注意点はあります。あまり多用するとコードの信頼性が落ちかねないので、基本的には普通の関数を使うことを推奨します。
#if、#elif、#elseディレクティブ
これらはC言語の制御文である、if文と似た働きをします。異なるのは、非該当となったソースコードはコンパイルさえされず、存在しないものと同等という扱いになることです。
#define MODE (0) // 動作モード [0=標準 / 1=調整 / 2=テスト]
void func(void)
{
#if (MODE == 1)
// 調整モード
...
#elif (MODE == 2)
// テストモード
...
#else
// 標準モード
...
#endif
}
またdefined演算子と組み合わせることで、複雑な条件を設けることもできます。
#define VERSION (1.2) // プログラムバージョン
#define MODE_TEST // テストモード
void func(void)
{
#if defined(MODE_TEST) && (VERSION >= 1.2)
// ver.1.2以降に使えるテストモード
...
#else
// 標準モード
...
#endif
}
#ifdef、#ifndefディレクティブ
#defineディレクティブでマクロが定義されているかどうかにより、ソースコードの有効/無効を切り替えます。#ifdefディレクティブはマクロが定義されているときに、#ifndefディレクティブはマクロが定義されていないときにソースコードが有効となります。
#define MODE_TEST // テストモード
void func(void)
{
#ifdef MODE_TEST
// テストモードでのみ有効
...
#endif
#ifndef MODE_TEST
// テストモードでは無効
...
#endif
}
#errorディレクティブ
#errorディレクティブはコンパイラーにエラーを出力させます。一般的には、設定してはいけないマクロの設定や組み合わせを防ぐのに使用します。
#define COM_BUFFER_MAX (2500)
void func(void)
{
#if COM_BUFFER_MAX > 2048
#error "COM_BUFFER_MAX error"
#endif
}
コメント