[C言語] 可変引数マクロの作り方

gccでは__VA_ARGS__を使って可変引数マクロを作ることができる。

ソースコード

```c: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;
}

```

実行結果

```text
num=2
num=3,4
num=2
num=3,4
SUM(2,3)=5
SUM(2,3,4)=9

```

Ideone
[http://ideone.com/WgDB6Q](http://ideone.com/WgDB6Q)

---

さらに、上記のやり方を応用して、１～６個の引数を持つマクロから、６個の引数を持つ関数を呼びだすマクロを作り出すことができる。

ソースコード

```c: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;
}

```

実行結果

```text

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](http://ideone.com/5CB5SR)

---

C++だとデフォルト引数が使えるので、__VA_ARGS__は使わないでできる。

```cpp: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;
}

```

実行例

```text

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](http://ideone.com/XOmZYB)

---

参考リンク

1. [C++] 可変個数引数マクロの作り方<br>
[http://d.hatena.ne.jp/tshino/20061123/1164307813](http://d.hatena.ne.jp/tshino/20061123/1164307813)
1. Overloading Macro on Number of Arguments<br>
[http://stackoverflow.com/questions/11761703/overloading-macro-on-number-of-arguments](http://stackoverflow.com/questions/11761703/overloading-macro-on-number-of-arguments)
1. C言語プログラミング マクロで可変引数を扱う方法とデバッグprintf<br>
[http://kaworu.jpn.org/kaworu/2008-06-23-1.php](http://kaworu.jpn.org/kaworu/2008-06-23-1.php)
1. C/C++での可変引数　(stdarg他)<br>
[http://www.02.246.ne.jp/~torutk/cxx/tips/varargs.html](http://www.02.246.ne.jp/~torutk/cxx/tips/varargs.html) <br>
\__VA_ARGS__と　GCC拡張の ##__VA_ARGS__　について
1. C++:2003 8.3.6 省略時実引数