¿Cuál es el uso posible para “#define for if (false) {} else for”?

En otra pregunta, acabo de ver esta pequeña perla de C sabiduría:

#define for if (false) {} else for 

que hizo que MSVC escupiera las advertencias de “expresión constante” para una statement bastante válida:

 for (int i = 0; i <= 10; i++) {...} 

Entiendo por qué MSVC se queja porque se expande a:

 if (false) {} else for (int i = 0; i <= 10; i++) {...} 

Simplemente no entiendo por qué los desarrolladores usarían ese pequeño fragmento. ¿Alguien tiene una idea?

Es para corregir un error en las versiones anteriores de Visual C ++ (v6.0 y anteriores). En el pasado, Visual C ++ había roto las reglas de scope sobre las variables declaradas dentro for sentencias:

 // This compiles in old versions of Visual C++, but it is in fact INVALID C++ for(int i = 0; ...) { ... } for(i = 0; ...) { } 

En otras palabras, Visual C ++ proporciona un ámbito como si fuera declarado fuera del ciclo, y le permite continuar utilizándolo después de finalizar el ciclo. Esto lleva a un código como el fragmento de arriba. En más comstackdores que cumplen con los estándares, ya no está dentro del scope de la definición del segundo ciclo for , por lo que el comstackdor emite un error acerca de que no estoy definido.

Para solucionar esto, algunas personas usaron esta macro (o macros equivalentes, equivalentes):

 #define for if(0) {} else for 

Esto cambia el ciclo for en esto:

 if(0) { } else for(int i = 0; ...) { ... } 

Esto coloca el bucle for en un nivel extra de scope, de modo que cualquier variable declarada en el bucle for quedará fuera del scope después, independientemente del error de Visual C ++. Esto garantiza que el mismo código comstack correctamente de forma coherente tanto en Visual C ++ como en comstackdores que cumplen con los estándares, y que el código incorrecto no se comstack correctamente de forma coherente.

También tenga en cuenta que si la macro se define en su lugar, así:

 // DO NOT USE #define for if(1) for 

Entonces, aunque eso tendría el mismo efecto para algún código simple, de repente provocaría que el siguiente código se comstackra incorrectamente:

 if(foo) for(...) { ... } else doSomething(); 

Porque si expandes la macro, obtienes esto:

 if(foo) if(1) for(...) { ... } else doSomething(); 

¡Y el else ahora coincide con el error if ! Entonces, el uso inteligente de usar if(0) {} else lugar de if(1) evita este problema.

Como nota final, #define for if(0) {} else for no causa recursión infinita, porque el preprocesador no reemplazará recursivamente la macro que está definiendo actualmente. Solo hará un reemplazo en este caso.

Según una búsqueda rápida, es un error en MSVC que se supera.

Como yo lo entiendo,

 for (int i = 0 ...) {.....} 
 // más tarde en el mismo nivel de scope en la misma función
 for (int i = 0 ...) {...}

causará una redefinición del error ‘i’.

Si el enunciado for está encerrado en una sentencia if, el comstackdor funciona como debería, de modo que no hay un error de redefinición (aparentemente interpreta los niveles de scope de ‘si’ pero no ‘para’)

Porque el comstackdor msvc maneja incorrectamente el scope de las variables declaradas en la instrucción for de forma predeterminada. Para evitar este comportamiento, tenía que desactivar las extensiones de Microsoft que luego hacían que los encabezados de ms no se comstackran.

Utilizo (sí, todavía uso vs6) uno diferente que no causa la advertencia en vs6, aunque el comstackdor de Intel todavía lo detecta.

 #define for switch(0) case 0: default: for 

No recuerdo de dónde lo saqué, pero dudo que lo haya inventado 😉

Sé que las otras respuestas ya dicen la mayor parte de esto, pero la ventana emergente dice que debe asegurarse de responder la pregunta.

El efecto ya fue descrito.

La razón para tenerlo es portar código de C ++ a MSVC. O también es muy útil si quieres que tu código de C ++ sea dependiente de las plataformas. Por ejemplo, lo desarrolló en Linux / MacOSX y ahora desea comstackrlo en MSVC.

Y también es muy útil para C ++. Por ejemplo:

 for(std::set::iterator i = myset.begin(); i != myset.end(); ++i) { // ... } for(int i = 0; i < N; ++i) { // ... } 

He visto el código MSVC que funcionó alrededor de esto haciendo:

 for(std::set::iterator i1 = myset.begin(); i1 != myset.end(); ++i1) { // ... } for(int i2 = 0; i2 < N; ++i2) { // ... } 

O:

 {for(std::set::iterator i = myset.begin(); i != myset.end(); ++i) { // ... }} {for(int i = 0; i < N; ++i) { // ... }} 

En ambos casos (imo) no es tan agradable. Y este #define es un pequeño truco para hacer que MSVC se comporte de manera más estándar.