2009-02-13 45 views
13

¿Es posible hacer algo como estoUse #ifdefs y # define a su vez, opcionalmente, una llamada de función en un comentario

#ifdef SOMETHING 
#define foo // 
#else 
#define foo MyFunction 
#endif 

La idea es que si se define algo, entonces llama a foo (...) se convierten en comentarios (o algo que no se evalúa ni compila); de lo contrario, se convierte en una llamada a MiFunción.

He visto __noop usado, pero no creo que pueda usarlo.

EDITAR (s):

No creo que realmente puede utilizar una macro aquí, porque MyFunction toma un número variable de argumentos.

Además, me gustaría que los argumentos NO se evalúen. (Así que hacer algo como comentando el cuerpo de MyFunction realmente no me dan lo que necesito, como todavía se evaluarán los argumentos)

+0

Vea si su compilador admite 'macros variadic'. – ChrisW

+0

_¿Por qué querrías hacer esto? Tal vez hay alguna otra forma de obtener lo que necesita. Porque sin contexto, lo que quiere hacer parece bastante peligroso ... – gimpf

+0

Para compiladores que no admiten macros variadic es bueno poder eliminar cadenas de depuración y llamadas a funciones. Ahorra mucho espacio ejecutable. – MSN

Respuesta

24

Prueba esto:

#ifdef SOMETHING 
#define foo(x) 
#else 
#define foo(x) MyFunction(x) 
#endif 

Si su función tiene varios argumentos, entonces:

#ifdef SOMETHING 
#define foo(x,y,z) 
#else 
#define foo(x,y,z) MyFunction(x,y,z) 
#endif 

Si su función tiene un número variable de argumentos, a continuación, el compilador puede apoyar a los llamados "macros variadic", así:

#ifdef SOMETHING 
#define foo(...) 
#else 
#define foo(...) MyFunction(__VA_ARGS__) 
#endif 

La razón por la que he visto este tipo de cosas usadas en la práctica es deshacerse de las funciones de registro de una compilación de lanzamiento. Sin embargo, consulte también Separate 'debug' and 'release' builds? en el que las personas cuestionan si debería incluso tienen compilaciones diferentes.


Como alternativa, en lugar de la redefinición de la llamada de función como nada, el comentario de Jonathan a esta respuesta sugiere hacer algo como lo siguiente:

#ifdef SOMETHING 
#define foo(...) do { if (false) MyFunction(__VA_ARGS__) } while (0) 
#else 
#define foo(...) do { if (true) MyFunction(__VA_ARGS__) } while (0) 
#endif 

El razonamiento para hacer esto es por lo que la llamada a la función es siempre compilado (para que no quede con errores gratuitos como referencias a variables eliminadas), pero solo se llama cuando sea necesario: vea Kernighan & Pike The Practice of Programming y también Goddard Space Flight Center programming standards.

Desde un archivo Debug.h (que se origina a partir de 1990, y por lo tanto no usar __VA_ARGS__):

/* 
** Usage: TRACE((level, fmt, ...)) 
** "level" is the debugging level which must be operational for the output 
** to appear. "fmt" is a printf format string. "..." is whatever extra 
** arguments fmt requires (possibly nothing). 
** The non-debug macro means that the code is validated but never called. 
** -- See chapter 8 of 'The Practice of Programming', by Kernighan and Pike. 
*/ 
#ifdef DEBUG 
#define TRACE(x) db_print x 
#else 
#define TRACE(x) do { if (0) db_print x; } while (0) 
#endif /* DEBUG */ 

Con C99, ya no hay necesidad de que el truco de doble paréntesis. El nuevo código no debe usarlo a menos que la compatibilidad con C89 sea un problema.

+0

¿Funcionará esto con una cantidad variable de argumentos? p.ej. foo (a, b, c) –

+0

Funcionará con un número de argumentos mayor que uno pero fijo. Para una cantidad variable de argumentos, Google y/o revise la documentación de su compilador para las denominadas "macros variadic". – ChrisW

+0

@ChrisW Si modifica su respuesta para usar una macro variadica, entonces _creo_ es exactamente lo que necesito :) –

0

Si no recuerdo mal, usted debe ser capaz de #define su macro a "nada" y que hará que el compilador de hacer caso omiso de esa llamada

#define foo() 

foo(); // this will be ignored 
5

Quizás una manera más fácil de hacer esto sería condicionalmente omitir el cuerpo de la función?

void MyFunction() { 
#ifndef SOMETHING 
    <body of function> 
#endif 
} 

A menos que específicamente no desea que una llamada a la función que se hará en absoluto, esto parece una manera limpia para lograr su objetivo.

+1

Pero los argumentos todavía se evaluarán ... –

+0

Es cierto. Creo que si no quiere que se evalúen los argumentos, puede que tenga que llegar hasta #ifdefindar todas las llamadas. La solución "#define foo (x)" también evaluará tus argumentos en la mayoría de los compiladores. – MattK

+0

No solo se evalúan los argumentos, sino que se incluyen los datos que no son muy agradables si la función es una función de registro y los argumentos son enormes cadenas que describen el funcionamiento de la aplicación. – sharptooth

2

Si, en el caso de que no desee foo llama, que lo definen como:

void foo() {} 

cualquier llamada a foo() debe ser optimizado manera.

+0

Creo que probablemente también deba declararlo en línea para garantizar que se optimice. Debería soportar varargs también, así que creo que esta es probablemente la mejor solución. – rmeador

+0

Depende del compilador. He visto que VC++ optimiza las funciones de ausente con código en ellas cuando podría determinar que no tenían efectos secundarios. Muy frustrante cuando intentas hacer benchmarks ;-) – Ferruccio

2

¿Qué pasa algo como lo siguiente:

#ifdef NDEBUG 
#define DEBUG(STATEMENT) ((void)0) 
#else 
#define DEBUG(STATEMENT) (STATEMENT) 
#endif 

Usted podría utilizar de esta manera para registrar los mensajes de depuración:

DEBUG(puts("compile with -DNDEBUG and I'm gone")); 

Una versión no genérica para la salida formateada con la depuración adicional la información que utiliza las macros variadas C99 y el identificador __func__ podría verse así:

#ifdef NDEBUG 
#define Dprintf(FORMAT, ...) ((void)0) 
#define Dputs(MSG) ((void)0) 
#else 
#define Dprintf(FORMAT, ...) \ 
    fprintf(stderr, "%s() in %s, line %i: " FORMAT "\n", \ 
     __func__, __FILE__, __LINE__, __VA_ARGS__) 
#define Dputs(MSG) Dprintf("%s", MSG) 
#endif 

Así es como tendrá que utilizar estas macros:

Dprintf("count = %i", count); 
Dputs("checkpoint passed"); 
3

Por desgracia, la actual versión de C++ no admite macros variadic.

Sin embargo, usted puede hacer esto:

#ifdef SOMETHING 
#define foo 
#else 
#define foo(args) MyFunction args 
#endif 

// you call it with double parens: 
foo((a, b, c)); 
+0

Hago esto con las funciones de registro de depuración para que (a) desaparezcan por completo en las compilaciones de producción, y (b) pueda pasar una cadena de formato y cualquier número de argumentos. –

1

No, el C++ y C Normas decir que no puede ser algo #define un comentario, por lo

#define foo // 

no va a funcionar.

1
#ifdef SOMETHING 
#define foo sizeof 
#else 
#define foo MyFunction 
#endif 

Supongo que foo es una función de estilo printf? De todos modos, esto no funcionará con una función de parámetro cero, pero si ese fuera el caso, ya sabrías qué hacer. Si realmente quieres ser anal, puedes usar (void)sizeof, pero eso probablemente sea innecesario.

0

¿Qué pasa en torno a cada llamada a MyFunction con

#ifdef SOMETHING 
myFunction(...); 
#endif 

?

+1

Eso se vuelve intolerablemente torpe después de la segunda invocación. No sigas esta ruta. –

2

Es probable que no desee hacer la simple "eliminación de código" como se sugiere, porque las personas que llaman esperarán que se produzcan los efectos secundarios de los argumentos . Éstos son algunos fragmentos de llamadas molestas que debería hacerle pensar:

// pre/post increment inside method call: 
MyFunction(i++); 

// Function call (with side effects) used as method argument: 
MyFunction(StoreNewUsernameIntoDatabase(username)); 

Si se va a desactivar MyFunction simplemente diciendo:

#define MyFunction(x) 

entonces los efectos secundarios que las personas que llaman esperaban se iría, y su código se rompería, y sería bastante difícil depurarlo.Me gusta la sugerencia "sizeof" anterior, y también me gusta la sugerencia de simplemente deshabilitar el cuerpo de MyFunction() a través de # ifdef, aunque eso significa que todas las personas que llaman obtienen la misma versión de MyFunction(). Desde su declaración de problema , supongo que no es realmente lo que quiere.

Si realmente necesita desactivar MyFunction() a través de preprocesador define en función de cada fuente en archivos, a continuación, lo haría así:

#ifdef SOMETHING 
#define MyFunction(x) NoOp_MyFunction(x) 

int NoOp_MyFunction(x) { } 
#endif 

incluso se podría incluir la implementación de NoOp_MyFunction() dentro de el origen & encabezados para MyFunction(). También tiene la flexibilidad para agregar información adicional de registro o depuración en NoOp_MyFunction() como .

+0

'sizeof' tiene los mismos efectos secundarios wrt. –

1

Soy un poco reacio a publicar esta respuesta porque su uso de macro hackers puede convertirse en la fuente de problemas. Sin embargo, si las llamadas a la función que quiere que desaparezcan siempre se usan solas en una instrucción (es decir, nunca forman parte de una expresión más grande), entonces algo como lo siguiente podría funcionar (y maneja varargs):

#ifdef SOMETHING 
#define foo (1) ? ((void) 0) : (void) 
#else 
#define foo MyFunction 
#endif 

lo tanto, si usted tiene la línea de código:

foo("this is a %s - a++ is %d\n", "test", a++); 

que va a terminar después de la etapa de preprocesamiento ya sea como:

MyFunction("this is a %s - a++ is %d\n", "test", a++); 

o

(1) ? ((void) 0) : (void)("this is a %s - a++ is %d\n", "test", a++); 

que convierte lista de parámetros del pseudo-función en un montón de expresiones separadas por el operador de coma que nunca será evaluado, ya que el condicional siempre devuelve el resultado ((void) 0).

Una variante de esto es algo parecido a lo que sugirió ChrisW y Jonathan Leffler:

#ifdef SOMETHING 
#define foo if (0) MyFunction 
#else 
#define foo if (1) MyFunction 
#endif 

Esta cifra es ligeramente diferente, ya que no requiere el compilador para apoyar las macros variadic (__VA_ARGS__).

Creo que esto puede ser útil para eliminar llamadas de función de seguimiento de depuración que generalmente nunca se combinan en una expresión más grande, pero más allá de eso, creo que es una técnica peligrosa.

Tenga en cuenta la posibilidad de problemas, especialmente si los parámetros en la llamada producen efectos secundarios (este es un problema general con las macros, no solo este truco). En el ejemplo, el a++ se evaluará solo si SOMETHING está definido en la compilación, de lo contrario no lo es. Entonces, si el código después de la llamada depende del valor de a para ser incrementado, una de las compilaciones tiene un error.

Cuestiones relacionadas