2009-03-25 32 views
158

Quiero escribir una macro en C que acepta cualquier número de parámetros, no un número específicoCómo hacer una macro variadic (número variable de argumentos)

ejemplo:

#define macro(X) something_complicated(whatever(X)) 

donde X es cualquier número de parámetros

Lo necesito porque whatever está sobrecargado y se puede llamar con 2 o 4 parámetros.

Intenté definir el macro dos veces, ¡pero la segunda definición sobrescribió la primera!

El compilador que estoy trabajando es g ++ (más específicamente, MinGW)

+6

¿Desea C o C++? Si está utilizando C, ¿por qué está compilando con un compilador de C++? Para usar las macros variadas C99 adecuadas, debe compilar con un compilador C que admita C99 (como gcc), no un compilador C++, ya que C++ no tiene macros variadic estándar. –

+0

Bueno, asumí que C++ es un súper conjunto de C a este respecto ... – hasen

+0

http://tigcc.ticalc.org/doc/cpp.html#SEC13 tiene una explicación detallada de las macros variadas. – Gnubie

Respuesta

244

C99 way, también compatible con el compilador de VC++.

#define FOO(fmt, ...) printf(fmt, ##__VA_ARGS__) 
+6

No creo que C99 requiera el ## antes de __VA_ARGS__. Eso podría ser simplemente VC++. –

+85

El motivo de ## antes de __VA_ARGS__ es que se traga la coma anterior en caso de que la lista de argumentos variables esté vacía, por ejemplo. FOO ("a") se expande a printf ("a"). Esta es una extensión de gcc (y vC++, tal vez), C99 requiere al menos un argumento para estar presente en lugar de la elipsis. – jpalecek

+83

'##' no es necesario y no es portátil. '#define FOO (...) printf (__ VA_ARGS __)' hace el trabajo de la manera portátil; el parámetro 'fmt' se puede omitir de la definición. – alecov

4

se explica por g ++ aquí, aunque es parte de C99 así debería funcionar para todo el mundo

http://www.delorie.com/gnu/docs/gcc/gcc_44.html

ejemplo rápido :

#define debug(format, args...) fprintf (stderr, format, args) 
+2

Las macros variadas de GCC no son macros variadas C99. GCC tiene macros variadas C99, pero G ++ no las admite, porque C99 no es parte de C++. –

+0

En realidad g ++ compilará macros C99 en archivos C++. Sin embargo, emitirá una advertencia si se compila con '-pedantic'. –

+2

No es C99. C99 usa __VA_ARGS__ macro). – qrdl

22

no creo que eso sea posible, usted podría fingir con parens dobles ... con tal de que no es necesario los argumentos individualmente.

#define macro(ARGS) some_complicated (whatever ARGS) 
// ... 
macro((a,b,c)) 
macro((d,e)) 
+0

C99 agrega macros variadas. –

+16

Si bien es posible tener una macro variadic, usar doble paréntesis es un buen consejo. –

+1

El compilador XC de Microchip no admite macros variadic, por lo que este truco de doble paréntesis es lo mejor que puede hacer. – gbmhunter

8
#define DEBUG 

#ifdef DEBUG 
    #define PRINT print 
#else 
    #define PRINT(...) ((void)0) //strip out PRINT instructions from code 
#endif 

void print(const char *fmt, ...) { 

    va_list args; 
    va_start(args, fmt); 
    vsprintf(str, fmt, args); 
     va_end(args); 

     printf("%s\n", str); 

} 

int main() { 
    PRINT("[%s %d, %d] Hello World", "March", 26, 2009); 
    return 0; 
} 

Si el compilador no entiende macros variadic, también se puede despojar de impresión con cualquiera de los siguientes:

#define PRINT // 

o

#define PRINT if(0)print 

Los primeros comentarios fuera las instrucciones PRINT, la segunda evita la instrucción PRINT debido a una condición NULL if. Si se establece la optimización, el compilador debe quitar las instrucciones nunca ejecutadas como: if (0) print ("hello world"); o ((nulo) 0);

+6

#define PRINT // no reemplazará PRINT con // – bitc

+7

#define PRINT si (0) imprimir no es una buena idea tampoco porque el código de llamada podría tener su propia opción- si para llamar IMPRIMIR. Mejor es: #define PRINT if (true); else print – bitc

+2

El estándar "no hacer nada, con gracia" es do {} while (0) – vonbrand

26

__VA_ARGS__ es la forma estándar de hacerlo. No use hacks específicos del compilador si no es necesario.

Estoy realmente molesto porque no puedo hacer ningún comentario sobre la publicación original. En cualquier caso, C++ no es un superconjunto de C. Es realmente tonto compilar su código C con un compilador de C++. No hagas lo que Donny Do no hace.

+3

* "Es realmente tonto compilar tu código C con un compilador C++" * => No lo consideran todos (incluido yo). Consulte, por ejemplo, las directrices básicas de C++: ** CPL.1: prefiera C++ a C **, [** CPL.2: si debe usar C, use el subconjunto común de C y C++, y compile el código C como C++ * *] (https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Rcpl-subset). Estoy en apuros para pensar en qué "C-solo-ismos" uno realmente necesita para hacer que valga la pena no programar en el subconjunto compatible, y los comités C y C++ han trabajado duro para hacer ese subconjunto compatible disponible. – HostileFork

+1

@HostileFork Aunque es bastante justo *, por supuesto * a los usuarios de C++ les gustaría fomentar el uso de C++. Otros no están de acuerdo, sin embargo; Linux Torvalds, por ejemplo, aparentemente ha rechazado varios parches de Linux-kernel propuestos que intentan reemplazar el identificador 'clase' con' klass' para permitir la compilación con un compilador de C++. También tenga en cuenta que hay algunas diferencias que lo harán tropezar; por ejemplo, el operador ternario no se evalúa de la misma manera en ambos idiomas, y la palabra clave 'inline' significa algo completamente diferente (como aprendí de una pregunta diferente). –

+0

Para proyectos de sistemas realmente multiplataforma como un sistema operativo, realmente desea adherirse a la estricta C, porque los compiladores de C son mucho más comunes.En sistemas integrados, todavía hay plataformas sin compiladores de C++. (¡Hay plataformas con solo compiladores de C pasibles!) Los compiladores de C++ me ponen nervioso, particularmente para los sistemas ciberfísicos, y supongo que no soy el único programador/programador de C embebido con esa sensación. – downbeat

Cuestiones relacionadas