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

  • 25
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

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 省略時実引数