studio - C/C++: cómo usar do-while(0); construir sin advertencias de compilador como C4127?
include c++ visual studio (20)
Aquí hay otro enfoque posible, que evita C4127, C4548 y C6319 (advertencia de análisis de código VS2013), y no requiere macros o pragmas:
static const struct {
inline operator bool() const { return false; }
} false_value;
do {
// ...
} while (false_value);
Esto se optimiza y compila sin advertencias en GCC 4.9.2 y VS2013. En la práctica, podría ir en un espacio de nombres.
A menudo utilizo do-while (0) build en mis #defines, por las razones que se describen en esta respuesta . También intento usar el nivel de advertencia más alto posible del compilador para detectar más problemas potenciales y hacer que mi código sea más robusto y multiplataforma. Así que normalmente uso -Wall
con gcc y /Wall
con MSVC.
Desafortunadamente, MSVC se queja de construir do-while (0):
foo.c(36) : warning C4127: conditional expression is constant
¿Qué debo hacer con esta advertencia?
¿Deshabilitarlo globalmente para todos los archivos? No parece ser una buena idea para mí.
Bueno, para mí, lo siguiente funciona sin la advertencia C4127:
#define ALWAYS_TRUE(zzsome) ((##zzsome)==(##zzsome))
void foo()
{
int a = 0;
while( ALWAYS_TRUE(a) )
{
}
}
Por supuesto, los compiladores son inteligentes y zzsome no debe ser una constante
Como señaló Michael Burr en la answer Carl Smotricz , para Visual Studio 2008+ puede usar __pragma :
#define MYMACRO(f,g) /
__pragma(warning(push)) /
__pragma(warning(disable:4127)) /
do { f; g; } while (0) /
__pragma(warning(pop))
Puede ponerlo en una línea (sin la /
s) si prefiere que las macros no se puedan leer.
Con las versiones más nuevas del compilador de MS, puede usar la supresión de advertencia:
#define MY_MACRO(stuff) /
do { /
stuff /
__pragma(warning(suppress:4127)) /
} while(0)
También puede presionar / desactivar / pop, pero suprimir es un mecanismo mucho más conveniente.
Debo decir que nunca me he molestado con la construcción de do..while en macros. Todo el código en mis macros está incluido entre llaves, pero sin el do - .. while. Por ejemplo:
#define F(x) /
{ /
x++; /
} /
int main() {
int a = 1;
F(a);
printf( "%d/n", a );
}
Además, mi propio estándar de codificación (y práctica informal durante años) ha sido hacer que todos los bloques, donde sea que estén, estén encerrados entre llaves, lo que también elimina más o menos el problema.
Encontré esta es la versión más corta
do {
// ...
}
while (([]() { return 0; })()) /* workaround for MSVC warning C4172 : conditional expression is constant */
No he comprobado si el compilador lo ha optimizado, pero supongo que sí.
Este "mientras (0)" es un truco y acaba de dar la vuelta para morderte.
¿Su compilador ofrece #pragma
para desactivar selectivamente y localmente los mensajes de error específicos? Si es así, esa podría ser una alternativa sensata.
Este error del compilador se corrigió en Visual Studio 2015 Actualización 1, incluso si las notas de la versión no lo mencionan.
Sin embargo, el error se explicó en una de las respuestas anteriores:
Resumen: esta advertencia (C4127) en este caso particular es un error del compilador sutil. No dude en deshabilitarlo.
Estaba destinado a detectar situaciones cuando la expresión lógica se evalúa como una constante en situaciones no obvias (como, por ejemplo, si (a == a && a! = A), y de alguna manera, convirtió mientras (verdadero) y otras construcciones útiles en inválidas .
Esto desactivará la advertencia y el compilador aún podrá optimizar el código:
static inline bool to_bool(const bool v) { return v; }
if (to_bool(0)) { // no warning here
dead_code(); // will be compiled out (by most compilers)
}
do { something(); } while(to_bool(0)); // no extra code generated
Hay una solución pero agregará más ciclos a su código. No use valor explícito en la condición while.
Puedes hacerlo así:
archivo1.h
extern const int I_am_a_zero;
#define MY_MACRO(foo,bar) /
do /
{ /
} /
while(I_am_a_zero);
la variable I_am_a_zero debe definirse en algún archivo .c.
De todos modos esta advertencia no aparece en GCC :)
Vea esta pregunta relacionada .
La advertencia se debe al while(false)
. Este site proporciona un ejemplo de cómo solucionar este problema. Ejemplo del sitio (tendrá que volver a trabajarlo para su código):
#define MULTI_LINE_MACRO_BEGIN do {
#define MULTI_LINE_MACRO_END /
__pragma(warning(push)) /
__pragma(warning(disable:4127)) /
} while(0) /
__pragma(warning(pop))
#define MULTI_LINE_MACRO /
MULTI_LINE_MACRO_BEGIN /
std::printf("Hello "); /
std::printf("world!/n"); /
MULTI_LINE_MACRO_END
Solo inserta tu código entre BEGIN y END.
Podría usar for
loop como:
for (;;) {
// code
break;
}
Macro:
#define BEGIN /
for (;;) {
#define END /
break; }
Puede usar #pragma warning para:
- salvar el estado
- desactivar la advertencia
- escribe el código ofensivo
- devolver la advertencia a su estado anterior
(necesita un # antes de los pragmas, pero SO está teniendo dificultades para lidiar con ellos y formatear al mismo tiempo)
#pragma warning( push )
#pragma warning( disable: 4127 )
// Your code
#pragma warning( pop )
Desea presionar / hacer estallar las advertencias en lugar de deshabilitar / habilitar porque no quiere interferir con los argumentos de la línea de comandos que pueden elegirse para activar / desactivar las advertencias (alguien puede usar la línea de comando para desactivar la advertencia, lo hace no quiero forzarlo de nuevo ... el código anterior trata de eso).
Esto es mejor que desactivar la advertencia globalmente, ya que puede controlarla solo por la parte que desea. También puedes hacer que forme parte de la macro.
Puede usar el operador de coma en lugar de do-while (0) construir para que la macro multi-instrucción se use en las expresiones. Entonces, en lugar de:
#define FOO(...) do { Statement1; Statement2; Statement3; } while(0)
Utilizar:
#define FOO(...) (Statement1, Statement2, Statement3)
Esto funciona independientemente de la plataforma y permite evitar la advertencia del compilador (incluso si se selecciona el nivel de advertencia más alto). Tenga en cuenta que en la coma que contiene macro (segundo FOO) el resultado de la última declaración (Statement3) sería el resultado de la macro completa.
Puedes usar
do {
// Anything you like
} WHILE_FALSE;
Y antes defina la macro WHILE_FALSE
siguiente manera:
#define WHILE_FALSE /
__pragma(warning(push)) /
__pragma(warning(disable:4127)) /
while(false) /
__pragma(warning(pop))
Verificado en MSVC ++ 2013.
Resumen: esta advertencia (C4127) en este caso particular es un error del compilador sutil. No dude en deshabilitarlo.
A fondo:
Estaba destinado a detectar situaciones cuando la expresión lógica se evalúa como una constante en situaciones no obvias (como, por ejemplo, if(a==a && a!=a)
, y de alguna manera, convirtió while(true)
y otras construcciones útiles en inválidas .
Microsoft recomienda usar for(;;)
para infinito bucle si desea tener esta advertencia activada, y no hay solución para su caso. Esta es una de las pocas advertencias de nivel 4 que las convenciones de desarrollo de mi empresa permiten inhabilitar.
Tal vez su código necesita más búhos :
do { stuff(); } while (0,0)
O menos fotogénico pero también menos productor de advertencias:
do { stuff(); } while ((void)0,0)
Tengo un patrón que basé una respuesta aquí y funciona en clang, gcc y MSVC. Lo estoy publicando aquí con la esperanza de que sea útil para otros y porque las respuestas aquí me ayudaron a formularlo.
#ifdef WIN32
# define ONCE __pragma( warning(push) ) /
__pragma( warning(disable:4127) ) /
while( 0 ) /
__pragma( warning(pop) )
#else
# define ONCE while( 0 )
#endif
Y lo uso así:
do {
// Some stuff
} ONCE;
Puedes usar esto en macros también:
void SomeLogImpl( const char* filename, int line, ... );
#ifdef NDEBUG
# define LOG( ... )
#else
# define LOG( ... ) do { /
SomeLogImpl( __FILE__, __LINE__, __VA_ARGS__ ); /
} ONCE
#endif
Esto también funciona para el caso señalado anteriormente, si F usa ''UNA VEZ'' en una función:
#define F( x ) do { f(x); } ONCE
...
if (a==b) F(bar); else someFunc();
Editar: Años más tarde, me doy cuenta de que olvidé agregar el patrón para el que escribí esta macro: el patrón "cambiar-como-un-goto":
do {
begin_some_operation();
if( something_is_wrong ) {
break;
}
continue_big_operation();
if( another_failure_cond ) {
break;
}
finish_big_operation();
return SUCCESS;
} ONCE;
cleanup_the_mess();
return FAILURE;
Esto le da una construcción try / finally-ish que es más estructurada que una modificación progresiva de su código de limpieza y devolución. El uso de esta macro ONCE en lugar de while (0) apaga VS hacia arriba.
Yo usaría
for(int i = 0; i < 1; ++i) //do once
{
}
Esto es equivalente a
do
{
}while(0);
y no da advertencias
#define STUFF for (bool b = true; b;) do {f(); g(); b = false;} while (b)
#define STUFF for (bool b = true; b;) do {f(); g(); b = false;} while (b)
?
#define STUFF for (;;) {f(); g(); break;}
#define STUFF for (;;) {f(); g(); break;}
?