Macro de preprocesador en C

Soy nuevo en la progtwigción en C, de hecho en la progtwigción, y recientemente aprendí el uso de macros con respecto a las directivas de preprocesador. Aunque me estoy familiarizando con él, el siguiente ejercicio que obtuve de un libro de texto me tropieza porque no obtengo la solución o la “lección para llevar” general.

Antes de escribir esta pregunta aquí, intenté ejecutar el código yo mismo agregando un poco printf() para obtener las respuestas correctas, pero ni siquiera se comstack. Ahora, antes de anotar la pregunta y el código, quiero hacer explícito que esta es una pregunta de autoaprendizaje y que no quiero ofender a la gente aquí con una pregunta que muchos encontrarán trivial. Solo quiero entender lo que está pasando.

El código es el siguiente

 int x=2, y=3, a=4,b=5; #define MAX(x, y) x > yx : y int c,d,e,f; c = MAX( a, 3 ); d = MAX( y, x ); e = MAX( ++x, 1 ); f = MAX( b, MAX (6, 7) ); 

Me piden que dé los valores de c, d, e y f. Hay una sugerencia adicional de que, aunque se denomina de esa manera, la macro anterior NO es el operador máximo. Por lo tanto, no creo que la suposición “obvia” de, por ejemplo, max (a, 3) = 4 sea correcta. En consecuencia, no sé qué está pasando.

EDIT: olvidé mencionar: sé que faltan paréntesis para el uso correcto. Pero me piden específicamente que evalúe los términos sin ellos. Por lo tanto, estoy confundido, ya que no sé exactamente cómo cambian los resultados y la función se comporta sin los incluidos.

Expandiendo la macro como está, obtenemos lo siguiente:

 Original Expanded -------- -------- c = MAX( a, 3 ); c = a>3 a : 3; d = MAX( y, x ); d = y>xy : x; e = MAX( ++x, 1 ); e = ++x>1 ++x : 1; f = MAX( b, MAX (6, 7) ); f = b>MAX (6, 7) b : MAX (6, 7); f = b>6>7 6 : 7 b : 6>7 6 : 7; 

La expansión de macros es simplemente una sustitución de texto simple: la syntax, el scope, la precedencia, la asociatividad, los valores, los efectos secundarios, etc. simplemente no se tienen en cuenta cuando se expande una macro (la expansión de la macro se produce antes de que el código fuente se envíe al comstackdor). .

Obviamente, ninguna de las expresiones expandidas de arriba se comstackrá. Para que eso suceda, necesitamos arreglar la macro MAX definiéndola como

 #define MAX( x, y ) x>y ? x : y 

Ahora obtenemos lo siguiente:

 Original Expanded -------- -------- c = MAX( a, 3 ); c = a>3 ? a : 3; d = MAX( y, x ); d = y>x ? y : x; e = MAX( ++x, 1 ); e = ++x>1 ? ++x : 1; f = MAX( b, MAX (6, 7) ); f = b>MAX (6, 7) ? b : MAX (6, 7); f = b>6>7 ? 6 : 7 ? b : 6>7 ? 6 : 7; 

Mejor. Las expresiones expandidas de arriba se comstackrán, pero las dos últimas no hacen nada parecido a lo que esperas. e no obtendrá el máximo de x y 1 , o bien obtendrá x+2 o 1 ( ? introduce un punto de secuencia, por lo que el comportamiento no está indefinido). f obtiene … algo , no puedo recordar la asociatividad de > y ?: casualidad, no estoy realmente dispuesto a desenterrarlo.

Nuevamente, las macros no toman en cuenta la precedencia y la asociatividad al expandir sus argumentos. Imagina que escribimos una macro CUBE que hace lo siguiente:

 #define CUBE(x) x * x * x 

y lo llamamos como

 y = CUBE( 2 + 3 ); 

Que se expande a

 y = 2 + 3 * 2 + 3 * 2 + 3; 

lo que nos da el valor 17, cuando probablemente esperábamos 125.

La forma correcta de definir la macro MAX es

 #define MAX( x, y ) ((x) > (y) ? (x) : (y)) 

No solo paréntesis de cada argumento, sino también paréntesis de toda la expresión. De esta manera, la precedencia y la asociatividad se conservan no solo si pasa expresiones complejas como argumentos, sino también si pasa esta macro como un argumento a otra (como en el último ejemplo):

 Original Expanded -------- -------- c = MAX( a, 3 ); c = ((a) > (3) ? (a) : (3)); d = MAX( y, x ); d = ((y) > (x) ? (y) : (x)); e = MAX( ++x, 1 ); e = ((++x) > (1) ? (++x) : (1)); f = MAX( b, MAX (6, 7) ); f = ((b) > (MAX (6, 7)) ? (b) : (MAX (6, 7))); f = ((b) > ((6) > (7) ? (6) : (7)) ? (b) : ((6) > (7) ? (6) : (7))); 

Esta vez, f será evaluado como esperas que sea.

La evaluación de e sigue siendo problemática ( ++x todavía se puede evaluar dos veces). Este es un problema en general con las macros que expanden sus argumentos más de una vez: los argumentos que tienen efectos secundarios se pueden evaluar varias veces, lo que llevará a respuestas incorrectas o un comportamiento indefinido.

Uso incorrecto del operador ternario.

 #define MAX(x,y) x>yx : y 

Debiera ser:

 #define MAX(x,y) (x>y) ? x : y 

Y para permitir expresiones más complejas:

 #define MAX(x,y) (((x)>(y)) ? (x) : (y)) 

Mencionas que no sabes lo que está pasando. Sólo hay una forma: ejecute sólo el preprocesador. Qué comstackdor estas usando? Suponiendo que gcc / clang puedes –

gcc -E filename.c

Esto solo ejecutará el preprocesador y le permitirá analizar lo que está sucediendo.

Por cierto, el código no se comstack porque cometió un error con el operador ternario: ¿debería ser x > y ? x : y x > y ? x : y .