2010-04-13 2 views
18

Если я определюсь макрос:Перебора макро переменных аргументов значение

#define foo(args...) ({/*do something*/}) 

есть какой-то способ фактически перебрать args, а не передать его другую функцию? Что-то вроде

#define foo(args...) \ 
     { \ 
      for (int i = 0; i < sizeof(args); ++i) { \ 
      /*do something with args[i]*/ \ 
      } \ 
     } 
+0

возможно дубликат [? Можно ли перебрать аргументы в вариативный макрос] (Http: // StackOverflow .com/questions/1872220/is-it-possible-to-iterate-over-arguments-in-variadic-macros) –

ответ

21

Не то, что я могу думать ...

Однако, если ваше приложение для этого обрабатывает переменное число аргументов одного и того же типа, например:

foo(0); 
foo(10, 20, 30); 
foo(1, 2, 3, 4, 5, 6, 7, 8, 9); 

и вы не возражаете использовать функцию, чтобы помочь, тогда есть некоторые полезные обманки, которые можно сделать.

Основная проблема заключается в том, что вы не можете просто передать эти аргументы прямо к функции varargs, потому что нет возможности для этой функции знать, сколько аргументов для чтения. И эта проблема может быть решена с некоторыми препроцессора магии:

#include <stdio.h> 
#include <stdarg.h> 

#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) 

/* C99-style: anonymous argument referenced by __VA_ARGS__, empty arg not OK */ 

# define N_ARGS(...) N_ARGS_HELPER1(__VA_ARGS__, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) 
# define N_ARGS_HELPER1(...) N_ARGS_HELPER2(__VA_ARGS__) 
# define N_ARGS_HELPER2(x1, x2, x3, x4, x5, x6, x7, x8, x9, n, ...) n 

# define foo(...) foo_helper(N_ARGS(__VA_ARGS__), __VA_ARGS__) 

#elif defined(__GNUC__) 

/* GCC-style: named argument, empty arg is OK */ 

# define N_ARGS(args...) N_ARGS_HELPER1(args, 9, 8, 7, 6, 5, 4, 3, 2, 1) 
# define N_ARGS_HELPER1(args...) N_ARGS_HELPER2(args) 
# define N_ARGS_HELPER2(x1, x2, x3, x4, x5, x6, x7, x8, x9, n, x...) n 

# define foo(args...) foo_helper(N_ARGS(args), args) 

#else 

#error variadic macros for your compiler here 

#endif 

static inline void foo_helper(unsigned int n_args, ...) 
{ 
    unsigned int i, arg; 
    va_list ap; 

    va_start(ap, n_args); 
    printf("%u argument(s):\n", n_args); 
    for (i = 0; i < n_args; i++) { 
    arg = va_arg(ap, unsigned int); 
    printf(" %u\n", arg); 
    } 
    va_end(ap); 
} 

int main(void) 
{ 
    foo(0); 
    foo(10, 20, 30); 
    foo(1, 2, 3, 4, 5, 6, 7, 8, 9); 
    return 0; 
} 

Выход:

$ gcc -W -Wall -std=c99 -pedantic -o va_macro va_macro.c 
$ ./va_macro 
1 argument(s): 
    0 
3 argument(s): 
    10 
    20 
    30 
9 argument(s): 
    1 
    2 
    3 
    4 
    5 
    6 
    7 
    8 
    9 
$ 
+1

Конечно, всеобъемлющий ответ, спасибо. Но я думаю, что воздержусь от использования этого метода :) –

+0

Мне нравится препроцессор, его просто так злобно хорошо – RichardBruce