LoginSignup
41
42

More than 5 years have passed since last update.

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

Posted at

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


参考リンク

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

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
41
42