vacio - objeto nulo c++
¿Por qué es(nulo) 0 una operación nula en C y C++? (5)
Incluso si es así, ¿por qué tipo lanzarlo al vacío? Además, en el caso de #define dbgprintf (void) 0, cuando se llama como dbgprintf ("¡Hola mundo!"); -> (vacío) 0 ("¡Hola mundo!"); - ¿Qué significa eso? - legends2k
Las macros reemplazan su código con otra cosa, por lo que si # definió dbgprint (que acepta x) como
vacío (0)
entonces no habrá reescritura de X en reemplazo, por lo que dbgprintf ("Helloworld") no se convertirá a (vacío) 0 ("Hello world"), sino a (void) 0; - no solo macro nombre dbgprint es reemplazado por (void) 0, sino que toda la llamada dbgprintf ("...")
He visto printfs de depuración en glibc que internamente se define como (void) 0
, si se define NDEBUG . Del mismo modo, el __noop
para el __noop
de Visual C ++ también está allí. El primero funciona en compiladores GCC y VC ++, mientras que el último solo en VC ++. Ahora todos sabemos que las declaraciones anteriores serán tratadas como ninguna operación y no se generará el código correspondiente; pero aquí es donde tengo una duda.
En el caso de __noop
, MSDN dice que es una función intrínseca proporcionada por el compilador. Llegando a (void) 0
~ ¿Por qué los compiladores lo interpretan como no op? ¿Es un uso complicado del lenguaje C o el estándar dice algo al respecto explícitamente? ¿O incluso eso tiene algo que ver con la implementación del compilador?
Creo que estás hablando de glibc , no de glib , y la macro en cuestión es la macro assert
:
En glibc <assert.h>
, con NDEBUG
(sin depuración) definido, assert
se define como:
#ifdef NDEBUG
#if defined __cplusplus && __GNUC_PREREQ (2,95)
# define __ASSERT_VOID_CAST static_cast<void>
#else
# define __ASSERT_VOID_CAST (void)
#endif
# define assert(expr) (__ASSERT_VOID_CAST (0))
#else
/* more code */
#endif
que básicamente significa assert(whatever);
es equivalente a ((void)(0));
y no hace nada
Del estándar C89 (sección 4.2):
El encabezado
<assert.h>
define la macroassert
y se refiere a otra macro,
NDEBUG
que no está definido por
<assert.h>
. SiNDEBUG
se define como un nombre de macro en el punto en el archivo de origen donde se incluye<assert.h>
, la macroassert
se define simplemente como
#define assert(ignore) ((void)0)
No creo que definir una macro de impresión de depuración para que sea igual a (void)0
tiene mucho sentido. ¿Puedes mostrarnos dónde se hace eso?
Cualquier expresión que no tenga ningún efecto secundario puede ser tratada como no operativa por el compilador, que no tiene que generar ningún código para ello (aunque puede). Sucede que el casting y luego no usar el resultado del reparto es fácil para el compilador (y los humanos) para ver que no tienen efectos secundarios.
En Windows, pruebo un código como este en Main.cpp:
#include <iostream>
#define TRACE ((void)0)
int main() {
TRACE("joke");
std::cout << "ok" << std::endl;
return 0;
}
Luego, construyo el archivo exe de la versión Release con salida Main.i. En el archivo Main.i, la macro TRACE se reemplazó por: ((void)0)("joke")
y Visual Studio da una advertencia: "advertencia C4353: extensión no estándar utilizada: constante 0 como expresión de función. Use ''__noop'' función intrínseca en su lugar ". Ejecute el archivo exe, la consola imprime caracteres "ok". Así que creo que todo está claro: la definición de macro TRACE [#define TRACE ((void) 0)] es ilegal según la sintaxis de c ++, pero el compilador de c ++ de Visual Studio admite este comportamiento como una extensión del compilador. Así que mi conclusión es la siguiente: [#define TRACE ((void) 0)] es una declaración ilegal de c ++, y en el mejor de los casos NO lo usas. Pero [#define TRACE (x) ((void) 0)] es una declaración legal. Eso es todo.
(void)0
(+ ;
) es una expresión C ++ válida, pero ''does-nothing'', eso es todo. No se traduce a la instrucción no-op
de la arquitectura de destino, es solo una declaración vacía como marcador de posición cuando el lenguaje espera una declaración completa (por ejemplo, como destino para una etiqueta de salto, o en el cuerpo de una cláusula if
).
EDITAR: (actualizado según el comentario de Chris Lutz)
Cabe señalar que cuando se usa como macro, di
#define noop ((void)0)
el (void)
evita que se use accidentalmente como un valor como
int x = noop;
Para la expresión anterior, el compilador lo marcará correctamente como una operación no válida. GCC escupe el error: void value not ignored as it ought to be
y VC ++ ladra ''void'' illegal with all types
.