2010-10-12 16 views
15

Encontré esto mientras leía un código fuente.C++ void cast y operador coma en un #define

#define MACRO(x) if((void) 0, (x)); else some_func(); 

No entiendo completamente las razones detrás de esa coma de operador y el molde de vacío. Esto probablemente tiene algo que ver con la protección macro, sé que (void)0 se usa a veces para proteger a las cascadas else s en macros como en if(...) then foo(); else (void)0.

¿Alguna idea de por qué la coma del operador está allí?

edición: estoy empezando a pensar que esto tiene algo que ver con la owl(0,0).

+0

¿Estás seguro de que incluso compila? – ronag

+0

@ronag: sí compila. el lanzamiento al vacío es un buen truco si te gusta escribir 'return f();' desde una función vacía cuando 'f' no está vacía. – ybungalobill

+1

Tengo curiosidad por saber si es equivalente a '#define MACRO (X) if (! (X)) {some_func()}' – Arun

Respuesta

8

Supongo que el truco se usa para evitar que el usuario declare variables en la condición if. Como usted probablemente sabe, en C++ es legal hacer esto

if (int i = some_func()) { 
    // you can use `i` here 
} 
else { 
    // and you can use `i` here 
} 

El uso del operador de coma en esa definición evitará el uso de macro como

MACRO(int i = some_func()); 

y obligar al usuario a utilizar sólo expresiones como argumento

+0

¿Quiere decir 'i' en lugar de' x', sí? – sje397

+0

Eso es lo que pensé, pero para citar a Charles, también es cierto aquí: "... what ((void) 0, x) is se supone que debe evitar que un simple par adicional de paréntesis no lo haga si ((x)); else algún_func(); ". – ybungalobill

+0

@ybungalobill: Sí, así es ... Y' (') extra lo resolvería en una mucho más simple. – AnT

4

La conversión nula definitivamente debe evitar llamar a un operator , sobrecargado ya que no se puede sobrecargar con un parámetro void. Esto garantiza que (void)0, no tiene ningún efecto.

¿Por qué el operador de coma está ahí? Una buena pregunta. Realmente no lo sé

+3

No entiendo. ¿Puede explicar con más detalle qué se supone que '((void) 0, x)' protege contra que un simple par de paréntesis adicionales no 'if ((x)); else algún_func(); '? –

+0

@Charles, tienes razón. – ybungalobill

2

Este se ve un poco como si alguien puede haber comenzado con un código que incluye un assert, pre-procesado, y se convirtió el resultado en una macro. Cuando se define NDEBUG, assert tiene que convertirse en casi nada, pero, sintácticamente, todavía tiene que producir algún código de marcador de posición. Por ejemplo, se le permite usarlo en una situación como:

assert(x), *x = 1; 

Al compilar esto con NDEBUG definido, todavía necesita para compilar, pero el assert no debe hacer nada. Para apoyar esto, assert se define típicamente algo como esto:

#undef assert 
#ifdef NDEBUG 
#define assert(x) ((void)0) 
#else 
#define assert(x) ((!!x) || __failassert(x, __FILE__, __LINE__)) 
#endif 

Por lo tanto, si alguien se inició con un código como anteriormente, y luego miró a la versión pre-procesado (con NDEBUG definida), que verían algo así como:

((void *)0), *x = 1; 

... y si no entendieron el código muy bien, podrían pensar que ((void)0) realmente significaba/lograba algo.

+0

Buen razonamiento, pero no estoy seguro de que ese sea el verdadero motivo. –

+0

No estoy * seguro * es la verdadera razón tampoco, de hecho, probablemente nadie más que el autor original puede hacer otra cosa que adivinar, e incluso él no puede recordar con seguridad tampoco ... –

+0

este "loco" funciona con original MACRO: #define CRAZY 0)); if ((1 – user396672