Help us understand the problem. What is going on with this article?

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

More than 5 years have passed since last update.

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 省略時実引数
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした