メインコンテンツへスキップ

値に応じて中身が変わるマクロ関数

·550 文字·
技術解説 C言語
komori-n
著者
komori-n
目次

書こうと思ったら意外と苦戦したのでメモ。

問題設定
#

マクロの設定値に応じて展開結果が変わるようなマクロ関数を作りたい。

具体的には、以下のようなマクロを考える。

#define A 0
#define B 1

#define CFG_1_MODE A
#define CFG_2_MODE B
#define CFG_3_MODE A

A, Bの2つのモードがあり、configすべき項目がいくつか(この例では3つ)ある状況を考える。

このとき、以下のように展開されるマクロ関数EXPAND(i)をうまく書きたい。

EXPAND(1)  // => IMPL_A(1)
EXPAND(2) // => IMPL_B(2)
EXPAND(3) // => IMPL_A(3)

IMPL_A, IMPL_Bに対し3項演算子は使えないものとする。(中身は単純な式ではないと仮定)

マクロ関数でなくても良いなら、以下のように#if~#endifを連打すれば簡単に実現できる。

#if CFG_1_MODE == A
IMPL_A(1)
#elif CFG_1_MODE == B
IMPL_B(1)
#endif
...

これをマクロ関数にするとなると意外と難しくなる。#define中では#ifは使えないので、次のように工夫する必要がある。

#define EXPAND(i) IMPL_TMP(CFG_##i##_MODE)(i)
#define IMPL_TMP(mode) IMPL_CAT(mode)
#define IMPL_CAT(mode) IMPL_##mode
#IMPL_0 IMPL_A
#IMPL_1 IMPL_B

CFG_##i##_MODEの値をIMPL_の後にくっつけて、分岐を実現する。

$ gcc -E cocoro-pyonpyon.c
# 1 "cocoro-pyonpyon.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 31 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 32 "<command-line>" 2
# 1 "cocoro-pyonpyon.c"
# 14 "cocoro-pyonpyon.c"
IMPL_A(1)
IMPL_B(2)
IMPL_A(3)

ちゃんと動いた。

これ、IMPL_0IMPL_1の部分がややダサいけどなんとかならないかな。値域が狭ければBOOST_PP_EQUALでなんとかなりそうだけど、一般の値を扱うとなると難しそう。僕には思いつかなかった。

コード
#

Related

ポインタのキャストでエンディアンを意識しないとバグる例
·558 文字
技術解説 C言語