2010-04-13 30 views
18

Si defino algunos macro:Retransmisión de macro Varargs valores

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

¿Hay alguna forma de bucle a través de realidad args en lugar de pasar a lo largo de otra función? Algo así como

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

posible duplicado de [? ¿Es posible iterar sobre argumentos a las macros variadic] (http: // stackoverflow .com/questions/1872220/is-it-possible-to-iterate-over-arguments-in-variadic-macros) –

Respuesta

21

No es que se me ocurre ...

Sin embargo, si la aplicación de este es el manejo de un número variable de argumentos del mismo tipo, por ejemplo:

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

y no te importa usar una función para ayudar, entonces hay algunos trucos útiles que se pueden hacer.

El principal problema aquí es que no se puede simplemente pasar estos argumentos directamente a una función varargs, porque no hay forma de que esa función sepa cuántos argumentos hay que leer. Y ese problema puede ser resuelto con un poco de magia preprocesador:

#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; 
} 

Salida:

$ 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

Una respuesta ciertamente completa, gracias. Pero creo que me abstendré de usar este método :) –

+0

Me encanta el pre-procesador, es tan malvado – RichardBruce