gccでは__VA_ARGS__を使って可変引数マクロを作ることができる。
ソースコード
test1.c
#include <stdio.h>
// 引数の数が違う、同じ関数に置き換える
#define DEBUG_PRINT(...) printf(__VA_ARGS__)
#define DEBUG_PRINT2(fmt, ...) printf(fmt, __VA_ARGS__)
// 引数の数が違う、別の関数に置き換える
#define GET_MACRO(_1,_2,_3,NAME,...) NAME
#define SUM(...) GET_MACRO(__VA_ARGS__, sum3, sum2)(__VA_ARGS__)
int sum2(int a,int b) { return a+b; }
int sum3(int a,int b,int c) { return a+b+c; }
int main(void) {
DEBUG_PRINT("num=%d\n",2);
DEBUG_PRINT("num=%d,%d\n",3,4);
DEBUG_PRINT2("num=%d\n",2);
DEBUG_PRINT2("num=%d,%d\n",3,4);
printf("SUM(2,3)=%d\n", SUM(2,3));
printf("SUM(2,3,4)=%d\n", SUM(2,3,4));
return 0;
}
実行結果
num=2
num=3,4
num=2
num=3,4
SUM(2,3)=5
SUM(2,3,4)=9
Ideone
http://ideone.com/WgDB6Q
さらに、上記のやり方を応用して、1~6個の引数を持つマクロから、6個の引数を持つ関数を呼びだすマクロを作り出すことができる。
ソースコード
test2.c
#include <stdio.h>
inline void logMsg(const char*fmt, int n1,int n2,int n3,int n4,int n5,int n6)
{
printf(fmt,n1,n2,n3,n4,n5,n6);
}
#define LOGMSG1(fmt,n1) logMsg(fmt,(int)n1,0,0,0,0,0)
#define LOGMSG2(fmt,n1,n2) logMsg(fmt,(int)n1,(int)n2,0,0,0,0)
#define LOGMSG3(fmt,n1,n2,n3) logMsg(fmt,(int)n1,(int)n2,(int)n3,0,0,0)
#define LOGMSG4(fmt,n1,n2,n3,n4) logMsg(fmt,(int)n1,(int)n2,(int)n3,(int)n4,0,0)
#define LOGMSG5(fmt,n1,n2,n3,n4,n5) logMsg(fmt,(int)n1,(int)n2,(int)n3,(int)n4,(int)n5,0)
#define LOGMSG6(fmt,n1,n2,n3,n4,n5,n6) logMsg(fmt,(int)n1,(int)n2,(int)n3,(int)n4,(int)n5,(int)n6)
#define GET_NAME(_1,_2,_3,_4,_5,_6,NAME,...) NAME
#define TRACE(fmt, ...) GET_NAME(__VA_ARGS__,LOGMSG6,LOGMSG5,LOGMSG4,LOGMSG3,LOGMSG2,LOGMSG1)(fmt,__VA_ARGS__)
int main(void) {
logMsg("%d,%d,%d,%d,%d,%d\n",1,2,3,4,5,6);
logMsg("%d,%d,%d,%d,%d\n", 1,2,3,4,5,0);
logMsg("%d,%d,%d,%d\n", 1,2,3,4,0,0);
logMsg("%d,%d,%d\n", 1,2,3,0,0,0);
logMsg("%d,%d\n", 1,2,0,0,0,0);
logMsg("%d\n", 1,0,0,0,0,0);
TRACE("%d,%d,%d,%d,%d,%d\n", 1,2,3,4,5,6);
TRACE("%d,%d,%d,%d,%d\n", 1,2,3,4,5);
TRACE("%d,%d,%d,%d\n", 1,2,3,4);
TRACE("%d,%d,%d\n", 1,2,3);
TRACE("%d,%d\n", 1,2);
TRACE("%d\n", 1);
return 0;
}
実行結果
1,2,3,4,5,6
1,2,3,4,5
1,2,3,4
1,2,3
1,2
1
1,2,3,4,5,6
1,2,3,4,5
1,2,3,4
1,2,3
1,2
1
Ideone
http://ideone.com/5CB5SR
C++だとデフォルト引数が使えるので、__VA_ARGS__は使わないでできる。
test3.cpp
#include <stdio.h>
#if ! defined(__cplusplus)
#error "not compiled with C++"
#endif
extern "C" void logMsg(const char*fmt, int n1,int n2=0,int n3=0,int n4=0,int n5=0,int n6=0);
extern "C" void logMsg(const char*fmt, int n1,int n2,int n3,int n4,int n5,int n6)
{
printf(fmt,n1,n2,n3,n4,n5,n6);
}
int main() {
logMsg("%d\n", 1);
logMsg("%d,%d\n", 1,2);
logMsg("%d,%d,%d\n", 1,2,3);
logMsg("%d,%d,%d,%d\n", 1,2,3,4);
logMsg("%d,%d,%d,%d,%d\n", 1,2,3,4,5);
logMsg("%d,%d,%d,%d,%d,%d\n", 1,2,3,4,5,6);
return 0;
}
実行例
1
1,2
1,2,3
1,2,3,4
1,2,3,4,5
1,2,3,4,5,6
デフォルト引数の値は、関数宣言にだけ含め、関数定義には書かないこと。
Ideone
http://ideone.com/XOmZYB
参考リンク
- [C++] 可変個数引数マクロの作り方
http://d.hatena.ne.jp/tshino/20061123/1164307813 - Overloading Macro on Number of Arguments
http://stackoverflow.com/questions/11761703/overloading-macro-on-number-of-arguments - C言語プログラミング マクロで可変引数を扱う方法とデバッグprintf
http://kaworu.jpn.org/kaworu/2008-06-23-1.php - C/C++での可変引数 (stdarg他)
http://www.02.246.ne.jp/~torutk/cxx/tips/varargs.html
__VA_ARGS__と GCC拡張の ##VA_ARGS について - C++:2003 8.3.6 省略時実引数