2009-08-17 13 views
5

¿Es posible definir una macro C/C++ "BUILD(a, i)" que se expande a "x[0], x[1], x[2], ..., x[i]"? Como enExpansión recursiva de macro a una secuencia

#define BUILD(x, 0) x[0] 
#define BUILD(x, 1) x[0], x[1] 
#define BUILD(x, 2) x[0], x[1], x[2] 
... 

Parece que BOOST_PP_ENUM_PARAMS podría hacer el trabajo. Supongo que podría #include boost, pero estoy interesado en saber cómo y por qué funciona, ¿alguien puede explicarlo?

quisiera llamar a una función f(int, ...) que toma argumentos N int x[i], 0 < = i < N. Donde N es conocido por ser ceil(sizeof(A)/sizeof(B)). Desafortunadamente, no puedo usar varargs o plantillas.

+0

relacionada: http://stackoverflow.com/questions/824639/variadic-recursive-preprocessor-macros-is-it-possible/893684 –

+0

¿Qué problema está realmente tratando de resolver? es decir. ¿Para qué se usará el resultado de esta macro? ¿Se podría cambiar ligeramente el uso para permitir una solución de plantilla (donde la recursión es posible)? –

+0

Ver mi última edición. –

Respuesta

14

Es posible, pero debe realizar un trabajo manual y tener un límite superior.

#define BUILD0(x) x[0] 
#define BUILD1(x) BUILD0(x), x[1] 
#define BUILD2(x) BUILD1(x), x[2] 
#define BUILD3(x) BUILD2(x), x[3] 
#define BUILD(x, i) BUILD##i(x) 

y observe que i debe ser un literal entero, no un valor calculado constante.

Por cierto, el preprocesador es más potente de lo que normalmente es, pero el uso de esa potencia es bastante complicado. Boost proporciona una biblioteca que facilita algunas cosas, incluida la iteración. Ver Boost Preprocessor Library. Hay otra biblioteca para tales cosas, pero su nombre se me escapa en este momento.

Editar: La biblioteca del preprocesador boost utiliza una técnica similar. Con trucos adicionales para resolver algunos problemas de casos de esquina, compartir macros de implementación entre instalaciones de nivel superior, solucionar errores de compilación, etc. ... la complejidad de impulso habitual que es normal en el contexto de una biblioteca de propósito general pero que a veces impide una fácil comprensión de los principios de implementación. Probablemente, el truco más notable es agregar un nivel indirecto para que, si el segundo parámetro puede ser una macro, se expanda. Es decir. con

#define BUILD_(x, i) BUILD##i(x) 
#define BUILD(x, i) BUILD_(x, i) 

uno puede hacer la llamada

#define FOO 42 
BUILD(x, FOO) 

que no es posible con lo que expuse.

+0

Gracias, es interesante cómo BUILD1..BUILD3 es casi idéntico ... no podría tener algo como #definir BUILD_ (x, j) BUILD_ (x, j-1), x [j] –

+0

No tendría una condición de detención, y las macros no pueden ser recursivas para arrancar. – Blindy

+0

+1 para una buena explicación! –

2

No, no lo es - las macros no pueden ser recursivas. Y las macros que publicó no son variadas, lo que significa "tener diferentes números de parámetros".

+1

Gracias, eliminé la etiqueta variadic. –

0

Ok, Tuve el mismo problema, mi objetivo era imprimir todos los valores de una matriz de N bytes utilizando macros. Supongo que tuviste más o menos el mismo problema. Si este fuera el caso, esta solución debería adaptarse a futuros problemas similares.

#define HEX_ARRAY_AS_STR(array, len) \ 
    ({ \ 
     int print_counter = 0; \ 
     print_buf = calloc(len*3+1, 1); \ 
     char *tmp_print_buf = print_buf; \ 
     uint8_t *array_flower = array; \ 
     while(print_counter++ < (len)){ \ 
      sprintf(tmp_print_buf, "%02X ", *(array_flower)++); \ 
      tmp_print_buf += 3; \ 
     } \ 
     print_buf; \ 
    }) 

#define eprintf(...) \ 
    do{ \ 
     char *print_buf; \ 
     printf(__VA_ARGS__); \ 
     if(print_buf) \ 
      free(print_buf); \ 
    }while(0) 

int 
main(int argc, char *argv[]) 
{ 
    uint8_t sample[] = {0,1,2,3,4,5,6,7}; 
    eprintf("%s\n", HEX_ARRAY_AS_STR(sample, 8)); 
    return 0; 
} 
+0

No, esto no es lo que estaba tratando de hacer. De todos modos, si siempre pasas una matriz a HEX_ARRAY_AS_STR podrías deshacerte del segundo parámetro usando sizeof (array)/sizeof (uint8_t) –

Cuestiones relacionadas