¿Qué es una forma portátil de implementar una declaración no operativa en C++?
noop (10)
De vez en cuando, se necesita una declaración de no-op en C ++. Por ejemplo, cuando se implementa assert()
que está deshabilitado en la configuración sin depuración (también vea esta pregunta ):
#ifdef _DEBUG
#define assert(x) if( !x ) { /
ThrowExcepion(__FILE__, __LINE__);/
} else {/
//noop here /
}
#else
#define assert(x) //noop here
#endif
Hasta ahora tengo la impresión de que la forma correcta es utilizar (void)0;
para un no-op:
(void)0;
sin embargo, sospecho que podría desencadenar advertencias en algunos compiladores, algo como C4555: expression has no effect; expected expression with side-effect
C4555: expression has no effect; expected expression with side-effect
advertencia de Visual C ++ de C4555: expression has no effect; expected expression with side-effect
que no se emite para este caso en particular, sino que se emite cuando no hay conversión para void
.
¿Es universalmente portátil? ¿Hay alguna manera mejor?
Sospecho que podría provocar advertencias en algunos compiladores
Es poco probable, ya que ((void)0)
es a lo que se expande la macro de assert
estándar cuando se define NDEBUG
. Por lo tanto, cualquier compilador que emita advertencias emitirá advertencias siempre que se compile el código que contiene aserciones para su publicación. Espero que sea considerado un error por los usuarios.
Supongo que un compilador podría evitar ese problema advirtiendo sobre su propuesta (void)0
mientras trata solo ((void)0)
especialmente. Por lo tanto, es mejor que uses ((void)0)
, pero lo dudo.
En general, lanzar algo para anular, con o sin los parens adjuntos adicionales, significa "ignorar esto" idiomáticamente. Por ejemplo, en el código C que convierte los parámetros de la función en void
para suprimir las advertencias de las variables no utilizadas. Entonces, en ese sentido también, un compilador que advirtió sería bastante impopular, ya que suprimir una advertencia solo le daría otra.
Tenga en cuenta que en C ++, los encabezados estándar pueden incluirse entre sí. Por lo tanto, si está utilizando un encabezado estándar, assert
puede haber sido definido por eso. Así que su código no es portátil en esa cuenta. Si está hablando de "universalmente portátil", normalmente debería tratar cualquier macro definida en cualquier encabezado estándar como un identificador reservado. Podría no definirlo, pero sería más sensato utilizar un nombre diferente para sus propias afirmaciones. Sé que es solo un ejemplo, pero no veo por qué querría definir assert
en una forma "universalmente portátil", ya que todas las implementaciones de C ++ ya lo tienen, y no hace lo que usted lo define. para hacer aqui
¿ do { } while(0)
? Sí, agrega código, pero estoy seguro de que la mayoría de los compiladores de hoy son capaces de optimizarlo.
; Se considera como estándar no-op. Tenga en cuenta que es posible que el compilador no genere ningún código a partir de él.
Creo que el objetivo aquí, y la razón para no definir la macro a nada, es requerir que el usuario agregue un ;
. Para ese propósito, en cualquier lugar que una declaración sea legal, (void)0
(o ((void)0)
, u otras variaciones de la misma) está bien.
Encontré esta pregunta porque tenía que hacer lo mismo en el ámbito global , donde una declaración sencilla es ilegal. Afortunadamente, C ++ 11 nos da una alternativa: static_assert(true, "NO OP")
. Esto se puede utilizar en cualquier lugar , y cumple mi objetivo de exigir un ;
despues de la macro (En mi caso, la macro es una etiqueta para una herramienta de generación de código que analiza el archivo de origen, por lo que al compilar el código como C ++, siempre será un NO-OP).
El no-op más simple es simplemente no tener ningún código:
#define noop
Entonces el código de usuario tendrá:
if (condition) noop; else do_something();
La alternativa que mencionas es también una no-op: (void)0;
, pero si vas a usar eso dentro de una macro, debes dejar el ;
Aparte para que la persona que llama agregue:
#define noop (void)0
if (condition) noop; else do_something();
(Si era parte de la macro, entonces habría un extra ;
allí)
Este código no se omitirá por optimización.
static void nop_func() { }
typedef void (*nop_func_t)();
static nop_func_t nop = &nop_func;
for (...)
{
nop();
}
Recomiendo usar:
static_cast<void> (0)
Y que hay con:
#define NOP() ({(void)0;})
o solo
#define NOP() ({;})
inline void noop( ) {}
Autodocumentación