sirve significa que programar programacion para ought not macro ignored hacer funciones ejemplo define como codigos c++ c c-preprocessor

significa - ¿Explicación de macro insegura de C++ FAQ?



void value not ignored as it ought to be arduino (4)

Según las preguntas frecuentes de C ++, las macros son malvadas :

[9.5] ¿Por qué debería usar las funciones en línea en lugar de las viejas macros #define?

Debido a que las macros #define son malvadas de 4 maneras diferentes: maldad # 1, maldad # 2, maldad # 3 y maldad # 4. A veces deberías usarlos de todos modos, pero siguen siendo malvados. A diferencia de las macros #define , las funciones en línea evitan errores macro infames, ya que las funciones en línea siempre evalúan todos los argumentos exactamente una vez. En otras palabras, invocar una función en línea es semánticamente igual que invocar una función regular, solo que más rápido:

// A macro that returns the absolute value of i #define unsafe(i) / ( (i) >= 0 ? (i) : -(i) ) // An inline function that returns the absolute value of i inline int safe(int i) { return i >= 0 ? i : -i; } int f(); void userCode(int x) { int ans; ans = unsafe(x++); // Error! x is incremented twice ans = unsafe(f()); // Danger! f() is called twice ans = safe(x++); // Correct! x is incremented once ans = safe(f()); // Correct! f() is called once }

Además, a diferencia de las macros, se verifican los tipos de argumentos y las conversiones necesarias se realizan correctamente.

Las macros son malas para tu salud; no los uses a menos que tengas que hacerlo.

¿Alguien puede explicar por qué es unsafe(x++) incrementos x dos veces? No soy capaz de averiguarlo.


Ejecutarlo a través del preprocesador muestra el problema. Usando gcc -E (también puede usar cpp -P , donde la opción -P también suprime # líneas generadas),

inline int safe(int i) { return i >= 0 ? i : -i; } int f(); void userCode(int x) { int ans; // increment 1 increment 2 (one of these) // | | | // V V V ans = ( (x++) >= 0 ? (x++) : -(x++) ); ans = ( (f()) >= 0 ? (f()) : -(f()) ); ans = safe(x++); ans = safe(f()); }

Como notas de ruido ingenuo, la función f() también es llamada dos veces por la macro unsafe . Tal vez es puro (no tiene efectos secundarios) por lo que no está mal , per se. Pero aún no es óptimo.

Entonces, dado que las funciones en línea son generalmente más seguras que las macros de función porque funcionan en el mismo nivel semántico con los otros elementos básicos: variables y expresiones; y para las constantes manifiestas, las enum menudo pueden ser más ordenadas ; ¿Cuáles son los buenos usos de las macros?

Establecer constantes conocidas solo en tiempo de compilación. Puede definir una macro desde la línea de comando al compilar. En lugar de

#define X 12

en el archivo fuente, puede agregar

-DX=12

al comando cc . También puede #undef X desde la línea de comando con -UX .

Esto permite cosas como la compilación condicional, ej.

#if X do this; #else do that; #endif while (loop);

para ser controlado por un archivo MAKE, tal vez generado con un script de configuración.

X-Macros . El uso más convincente para X-Macros, IMO, es asociar identificadores enum con cadenas imprimibles. Si bien parece divertido al principio, reduce los problemas de duplicación y sincronización con este tipo de definiciones paralelas.

#define NAMES(_) _(Alice) _(Bob) _(Caravaggio) _(DuncanIdaho) #define BARE(_) _ , #define STRG(_) #_ , enum { NAMES(BARE) }; char *names[] = { NAMES(STRG) };

Observe que puede pasar el nombre de una macro como un argumento a otra macro y luego llamar a la macro pasada usando el argumento como si fuera una macro (porque es uno). Para más sobre X-Macros, vea esta pregunta .


El preprocesador reemplaza la macro antes de la compilación.

El compilador ve esto:

( (x++) >= 0 ? (x++) : -(x++) )


Las macros efectivamente copian / pegan antes de compilar el programa.

unsafe(x++)

Se convertiría

( (x++) >= 0 ? (x++) : -(x++) )


unsafe(x) evalúa la expresión x dos veces. Una vez para determinar su valor de verdad, y luego una segunda vez en una de las dos ramas del operador ternario. La función en línea safe recibe un argumento evaluado: la expresión se evalúa una vez antes de la llamada a la función, y la llamada a la función funciona con variables locales.

unsafe no es tan inseguro como podría ser. El operador ternario introduce un punto de secuencia entre la evaluación de la prueba y la evaluación de la expresión consecuente o alternativa. unsafe(x++) incrementará confiablemente x dos veces, aunque, por supuesto, el problema es que este comportamiento es inesperado. En general, las macros que expanden una expresión más de una vez no tienen esta seguridad. Por lo general, ¡producen un comportamiento franco e indefinido!

Alrededor de 1999 produje un módulo de módulo de biblioteca para capturar usos de macros con efectos secundarios.

Por lo tanto, puede escribir macros "maléficas" y usarlas, y la máquina detectará situaciones en las que se utilicen accidentalmente con argumentos que tengan efectos secundarios (siempre que tenga una cobertura de código adecuada para alcanzar esos usos en tiempo de ejecución).

Aquí está el programa de prueba, unsafe.c . Tenga en cuenta que incluye un archivo de encabezado sfx.h y utiliza una macro SFX_CHECK en la secuencia de token de expansión unsafe :

#include "sfx.h" #define unsafe(i) / ( (SFX_CHECK(i)) >= 0 ? (i) : -(i) ) inline int safe(int i) { return i >= 0 ? i : -i; } int f(void) { return 0; } int main(void) { int ans; int x = 0; ans = unsafe(x++); // Error! x is incremented twice ans = unsafe(f()); // Danger! f() is called twice ans = safe(x++); // Correct! x is incremented once ans = safe(f()); // Correct! f() is called once }

Compilamos todo y ejecutamos desde un intérprete de comandos de shell de Linux:

$ gcc unsafe.c hash.c except.c sfx.c -o unsafe $ ./unsafe unsafe.c:22: expression "x++" has side effects unsafe.c:23: expression "f()" may have side effects

Tenga en cuenta que x++ ciertamente tiene efectos secundarios, mientras que f puede o no. Entonces los mensajes tienen una redacción diferente. Una función que se llama dos veces no es necesariamente un problema, porque una función puede ser pura (no tener efectos secundarios).

Puede obtenerlo here si tiene curiosidad sobre cómo funciona. Hay una penalización de tiempo de ejecución si la depuración está habilitada; por supuesto, SFX_CHECK se puede deshabilitar por lo que no hace nada (de forma similar a assert ).

La primera vez que se SFX_CHECK una expresión protegida SFX_CHECK , se analiza para determinar si podría tener efectos secundarios. Como este análisis se realiza sin ningún acceso a la información de la tabla de símbolos (cómo se declaran los identificadores), es ambiguo. El analizador persigue múltiples estrategias de análisis. Retroceder se realiza usando una biblioteca de manejo de excepciones basada en setjmp/longjmp . Los resultados del análisis se almacenan en una tabla hash codificada en la expresión textual para una recuperación más rápida en futuras evaluaciones.