"C Trampas y Defectos"----Capítulo 6 El Preprocesador

Punto clave: Las macros solo actúan sobre el texto del programa.

6.1 Los espacios en las definiciones de macro no se pueden ignorar

Observe la siguiente definición de macro:

#define f (x) ((x)-1)

f(x) representa

(x) ((x)-1)

y queremos que represente

((x)-1)

¡La razón es que hay un espacio adicional entre la f y la siguiente (x)! Entonces, la forma correcta de definirlo es:

#define f(x) ((x)-1)

Esta regla no se aplica a las llamadas a macros, sino solo a las definiciones de macros. Entonces, después de completar la definición de macro anterior, tanto f(3) como f(3) se evalúan como 2. Nota: La llamada a la función es exactamente la misma, es decir, si definimos la función SUMA, entonces el resultado de evaluar SUMA(1,2) y SUMA(1,2) es 3.

6.2 Las macros no son funciones

Nota: Cada parámetro y la expresión de resultado completa en la definición de macro se encuentran entre paréntesis. Pero todavía hay otros problemas, como los operadores de autoincremento y autodecremento de los efectos secundarios. Siempre que aparezcan una vez, realizarán un autoincremento o un autodecremento. En el análisis final, porque la macro es un reemplazo de texto, **Para garantizar que los parámetros de la macro no tengan efectos secundarios. ** Este no es el caso de las funciones, el operador de incremento o decremento en el argumento de la función solo se ejecutará una vez, por lo que es necesario distinguir entre funciones y macros.

6.3 Las macros no son sentencias

Supongamos que definimos una macro que puede incluir el nombre del archivo y el número de línea donde falló la afirmación en el mensaje de error, es decir

assert(x<y);

No haga nada cuando x sea mayor que y, de lo contrario termine el programa.

Si lo definimos así:

#define assert(e) if(!e) assert_error(__FILE,__LINE__)

Pero se produce un error cuando nos encontramos con la siguiente situación:

if(x > 0 && y > 0)
	assert(x > y);
else
	assert(y > x);

La notación anterior se ve así cuando se expande:

if(x > 0 && y > 0)
	if(!(x>y)) assert_error("foo.c",37);
else
	if(!(y>x)) assert_error("foo.c",39);

Después de sangrar el código anterior, se ve así:

if (x > 0 && y > 0)
		if (!(x > y)) assert_error("foo.c", 37);
		else
			if (!(y > x)) assert_error("foo.c", 39);

Obviamente, el código anterior es completamente diferente de lo que queremos expresar.

Por supuesto, parece que podemos usar llaves para encerrar la macro en la definición de la afirmación de la macro, lo que puede evitar este tipo de problemas:

#define assert(e)\
	{if(!e) assert_error(__FILE,__LINE__);}

Sin embargo. Esto traerá nuevos problemas.El ejemplo que mencionamos anteriormente se convierte en:

if(x > 0 && y > 0)
	{ if(!(x<y)) assert_error("foo.c",37);};
else
	{ if(!(y > x)) assert_error("foo.c",39);};

Un punto y coma antes del else es un error de sintaxis. Una solución a este problema es agregar un punto y coma a la llamada de afirmación, pero este uso es un poco "raro":

y = distence(p,q);
assert(y>0)
x = sqrt(y);

La definición correcta de la afirmación macro es bastante contraria a la intuición, esta definición parece una expresión, no una declaración:

#define assert(e)\
	((void)((e)||_assert_error(__FILE__,__LINE__)))

Esta definición en realidad aprovecha la propiedad de que el operador || evalúa ambos operandos secuencialmente.

6.4 Las macros no son definiciones de tipo

Las macros son simples reemplazos de texto, pero los typedefs definen nuevos tipos, que tienen el mismo estado que int, float, etc.

práctica

  1. P: Utilice una macro para implementar una versión de max donde los argumentos de max sean todos enteros, lo que requiere que estos argumentos enteros se evalúen solo una vez en la definición de macro max.

    responder:

    static int max_temp1,max_temp2;
    #define max(p,q) (max_temp1 = (p),max_temp2 = (q),\
    	max_temp1>max_temp2? max_temp1:max_temp2)
    

    La definición anterior funciona bien siempre que la macro max no esté anidada: en el caso de llamadas anidadas a la macro max, no funciona.

  2. Pregunta: ¿Se (x) ((x) - 1)puede llamar a esta expresión una expresión válida?

    Respuesta: Es posible, y hay dos situaciones:

    El primer caso:

    typedef int x;
    (x) ((x)-1);
    //等价于下面的表达式
    (int) ((int)-1)
    

    Segundo caso:

    x es un puntero de función, x apunta a un elemento de una matriz de punteros de función

    typedef void(*T)(void*);
    T x;
    

Supongo que te gusta

Origin blog.csdn.net/m0_57304511/article/details/123758784
Recomendado
Clasificación