C言語のマクロはとても便利ですが、落とし穴も多くあります。このページはマクロのサンプル集です。
マクロのサンプル集です。詳細はソースのコメントをご参照ください。
/**
* @file macro.h
* @brief マクロのサンプル集.
*/
#ifndef MACRO_H
#define MACRO_H
/*
SWAP - 変数入替 -
*/
/**
* 2つの変数の内容を入れ替える.
* 変数の型は引数typeで指定可能.
* @param [in] type 入れ替え対象の変数の型
* @param [in] a 入れ替え対象の変数1
* @param [in] b 入れ替え対象の変数2
* @retval なし
* @attention 引数は複数回評価される.
*/
#define SWAP(type, a, b) \
do {type tmp = a; a = b; b = tmp;} while (0)
/*
XOR_SWAP - 変数入替(XOR交換) -
*/
/**
* 2つの変数の内容をXOR交換アルゴリズムで入れ替える.
* @param [in] a 入れ替え対象の変数1
* @param [in] b 入れ替え対象の変数2
* @retval なし.
* @attention 交換対象の変数は整数(char含む)のみ可.
* @attention 同じ変数を指定すると結果は0となる.
* @attention 一時変数を用いて交換する方法よりも,
* @attention 高速に動作する可能性があるため,
* @attention 処理速度に問題がある際には検討の価値がある.
*/
#define XOR_SWAP(a, b) \
do {a ^= b; b ^= a; a ^= b;} while (0)
/*
MAX - 最大値取得 -
*/
/**
* 指定された2つの引数のうち,最大のものを返す.
* @param [in] a 最大値を選ぶ対象の変数1
* @param [in] b 最大値を選ぶ対象の変数2
* @retval 最大値
* @attention 引数は複数回評価される.
*/
#define MAX(a, b) ((a) > (b) ? (a) : (b))
/*
MAX3 - 最大値取得 -
*/
/**
* 指定された3つの引数のうち,最大のものを返す.
* @param [in] a 最大値を選ぶ対象の変数1
* @param [in] b 最大値を選ぶ対象の変数2
* @param [in] c 最大値を選ぶ対象の変数3
* @retval 最大値
* @attention 引数は複数回評価される.
*/
#define MAX3(a, b, c) ((a) > (MAX(b, c)) ? (a) : (MAX(b, c)))
/*
MIN - 最小値取得 -
*/
/**
* 指定された2つの引数のうち,最小のものを返す.
* @param [in] a 最小値を選ぶ対象の変数1
* @param [in] b 最小値を選ぶ対象の変数2
* @retval 最小値
* @attention 引数は複数回評価される.
*/
#define MIN(a, b) ((a) < (b) ? (a) : (b))
/*
MIN3 - 最小値取得 -
*/
/**
* 指定された3つの引数のうち,最小のものを返す.
* @param [in] a 最小値を選ぶ対象の変数1
* @param [in] b 最小値を選ぶ対象の変数2
* @param [in] c 最小値を選ぶ対象の変数3
* @retval 最小値
* @attention 引数は複数回評価される.
*/
#define MIN3(a, b, c) ((a) < (MIN(b, c)) ? (a) : (MIN(b, c)))
/*
IN4 - 集合要素判定 -
*/
/**
* 指定の集合に属する要素かを判定する.
* 判定対象xがa〜dのいずれかなら真を返却.
* @param [in] x 判定対象
* @param [in] a 集合要素1
* @param [in] b 集合要素2
* @param [in] c 集合要素3
* @param [in] d 集合要素4
* @retval 要素なら真.要素でなければ偽
* @attention 引数は複数回評価される.
*/
#define IN4(x, a, b, c, d) ((x) == a || (x) == b || (x) == c || (x) == d)
/*
INSIDE - 範囲内判定 -
*/
/**
* 指定の範囲内かを判定する.
* 判定対象xがa〜bの範囲内なら真を返却.
* @param [in] x 判定対象
* @param [in] a 範囲(小)
* @param [in] b 範囲(大)
* @retval 範囲内なら真.範囲外なら偽
* @attention 範囲の引数はa<=bであること.
* @attention 引数は複数回評価される.
*/
#define INSIDE(x, a, b) ((x) >= a && (x) <= b)
/*
INCREMENT - インクリメント -
*/
/**
* 引数に1を足す.その際,指定の最大値になったら0に戻す.
* @param [in] a インクリメント対象の変数
* @param [in] max 最大値
* @retval 1足された数
* @attention 返却値はmaxにはならない.
* @attention 1足した後の値がmaxなら0が返却される.
*/
#define INCREMENT(a, max) ((a) = ((a) + 1) % (max))
/*
DECREMENT - デクリメント -
*/
/**
* 引数から1を引く.0以下が渡された場合は,指定の最大値を返す.
* @param [in] a デクリメント対象の変数
* @param [in] max 最大値
* @retval 1引かれた数
* @attention 返却値はmax未満.
* @attention 1引いた後の値が負ならmax-1を返却.
*/
#define DECREMENT(a, max) \
(((a) = (a) - 1) < 0 ? ((a) = (max) - 1) : (a))
/*
PRINT_VARIABLE - 変数内容出力 -
*/
/**
* 変数名とその内容を指定のフォーマットで出力する.
* @param [in] a 出力対象の変数
* @param [in] f フォーマット文字列
* @retval 出力した文字数。エラー発生の場合は負数
*/
#define PRINT_VARIABLE(a, f) printf(#a " : " f "\n", a)
/*
ELEMENT_NUM - 配列要素数取得 -
*/
/**
* 配列の要素数を取得する.
* @param [in] array 配列名
* @retval 配列の要素数
* @attention 引数にポインタは指定不可.
*/
#define ELEMENT_NUM(array) (sizeof(array) / sizeof((array)[0]))
/*
MEMBER_SIZE - 構造体メンバサイズ取得 -
*/
/**
* 指定された構造体のメンバのサイズを返す.
* @param [in] type 構造体
* @param [in] member 構造体のメンバ
* @retval 指定された構造体のメンバのサイズ
*/
#define MEMBER_SIZE(type, member) (sizeof(((type*)0)->member))
/*
BEEP - 警告音 -
*/
/**
* 警告音を鳴らす.
* @param なし
* @retval 出力文字数.失敗の場合EOF
*/
#define BEEP() (fputc('\a', stderr))
/*
CALC_CLOCK - 処理時間表示 -
*/
/**
* 処理にかかったプロセッサ時間を出力する.
* 引数にはソースコードとループ回数を指定する.
* 使用例:CALC_CLOCK(a = sin(a), 1000000UL);
* @param [in] code ソースコード
* @param [in] n ループ回数
* @retval なし
*/
#define CALC_CLOCK(code, n) do { \
int i; \
clock_t t = clock(); \
for (i=0;i<(n);i++) { code; } \
printf("%d\n", clock() - t); \
} while (0)
/**
* 静的アサートで使用するテンポラリのマクロ1.
*/
#define STATIC_ASSERT_JOIN(x, y) STATIC_ASSERT_JOIN_AGAIN(x, y)
/**
* 静的アサートで使用するテンポラリのマクロ2.
*/
#define STATIC_ASSERT_JOIN_AGAIN(x, y) x ## y
/*
STATIC_ASSERT - 静的アサート1 -
*/
/**
* 与えられた定数式が偽ならば,コンパイルエラーを発生させる.
* 与えられた式が偽ならば,配列を要素数が負でtypedef,
* コンパイルエラーを発生させることにより静的アサートを実現する.
* 識別子に行数を加えているのは,複数のtypedefを可能にするため.
* @param [in] e 判定対象の定数式
* @retval なし
*/
#define STATIC_ASSERT(e) \
typedef char STATIC_ASSERT_JOIN(ASSERTION_AT_LINE_, __LINE__) [(e) ? 1 : -1]
/*
STATIC_ASSERT_2 - 静的アサート2 -
*/
/**
* 与えられた定数式が偽ならば,コンパイルエラーを発生させる.
* 関数のextern宣言を利用しての静的アサート.
* @param [in] e 判定対象の定数式.
* @retval なし.
*/
#define STATIC_ASSERT_2(e) \
extern void STATIC_ASSERT_DUMMY_FUNCTION(int ASSERTION_FAILED[(e) ? 1 : -1])
/*
STATIC_ASSERT_3 - 静的アサート3 -
*/
/**
* 与えられた定数式が偽ならば,コンパイルエラーを発生させる.
* enumを利用しての静的アサート.
* @param [in] e 判定対象の定数式.
* @retval なし.
*/
#define STATIC_ASSERT_3(e) \
enum { STATIC_ASSERT_JOIN(ASSERTION_AT_LINE_,__LINE__) \
= sizeof(struct { char STATIC_ASSERT_JOIN(ASSERTION_AT_LINE_,__LINE__) [(e) ? 1 : -1]; }) }
/*
UNUSED_PARAMETER - 未使用引数の警告回避 -
*/
/**
* 未使用の仮引数に対するワーニングを回避する.
* @param [in] p 未使用の仮引数.
* @retval なし.
*/
#define UNUSED_PARAMETER(p) ((void)(p))
/*
* ALIGN_64 - 64アライメント -
*/
/**
* 指定された値を64毎にアライメントして返す.
* @param [in] n アライメント対象の数.
* @retval アライメントされた値.
* @attention 63を加え、63のビット反転値で論理積をとることによりアライメントする.
* この方式はアライメントの単位が2の累乗数であれば使用可能.
* 例えば32単位でアライメントするなら31を加え、31のビット反転値で論理積をとる.
*/
#define ALIGN_64(n) (((n) + 63U) & ~63U)
/*
* ALIGN_N - 汎用アライメント -
*/
/**
* 指定された値をアライメントして返す.
* @param [in] n アライメント対象の数.
* @param [in] a アライメント単位.
* @retval アライメントされた値.
* @attention アライメントの単位が2の累乗数でない場合に使用する.
*/
#define ALIGN_N(n, a) (((n) % (a)) ? ((n) + ((a) - (n) % (a))) : (n))
#endif /* MACRO_H */