Macros de C y uso de argumentos entre paréntesis

4 minutos de lectura

avatar de usuario
rubixibuc

Ejemplo

#define Echo(a)  a
#define Echo(a) (a)

Me doy cuenta de que probablemente no haya una diferencia significativa aquí, pero ¿por qué querrías incluir el a entre paréntesis dentro del cuerpo de la macro? ¿Cómo lo altera?

  • posible duplicado de La necesidad de paréntesis en macros en C

    – Palec

    29 de abril de 2015 a las 8:35

  • La pregunta La necesidad de paréntesis en macros en C es un duplicado de esto, en lugar de viceversa, y ahora se cierra como tal.

    –Jonathan Leffler

    10 de febrero de 2018 a las 20:58

  • Preguntas relacionadas: ¿Podemos eliminar los paréntesis alrededor de los argumentos en las definiciones de macros de C? y ¿Cuándo se pueden omitir los paréntesis alrededor de los argumentos en las macros?

    –Jonathan Leffler

    10 de febrero de 2018 a las 21:01

avatar de usuario
cnicutar

Supongamos que tienes

#define mul(x, y)  x * y

¿Qué pasa si digo:

mul(a + 5, 6); /* a + 5 * 6 */

Ahora, si cambio ligeramente la macro:

#define mul(x, y)  ((x) * (y))
mul(a + 5, 6); /* ((a + 5) * (6)) */

Recuerde, los argumentos no se evalúan ni nada, solo se realiza la sustitución textual.

EDITAR

Para obtener una explicación sobre cómo tener la macro completa entre paréntesis, consulte el enlace publicado por Nate CK.

  • Gracias, estaba confundido porque en el libro que estoy usando, la forma en que los usaron parecía redundante. Tenían algo como esto foo(bar) (bar)->algo, ¿serían necesarios aquí?

    – rubixibuc

    25 de agosto de 2011 a las 7:30


  • probablemente te refieres foo(bar) (bar)->somethingy sí, son necesarios.

    – cnicutar

    25 de agosto de 2011 a las 7:31

  • Sry para preguntar, pero ¿cómo es necesario allí?

    – rubixibuc

    25 de agosto de 2011 a las 7:33

  • Leí toda la página vinculada y todavía no veo cómo podría analizarse mal

    – rubixibuc

    25 de agosto de 2011 a las 7:34


  • Supongamos que tiene una serie de estructuras y, por alguna razón, no foo(bar+5). Eso estaría perfectamente bien si foo fuera una función, pero si es una macro sin el paréntesis, terminará como bar+5->something. similares si bar es un puntero a un puntero, y lo haces foo(*bar) que termina como *bar->something que ciertamente está mal, querrás (*bar)->something

    – nos

    25 de agosto de 2011 a las 7:41

avatar de usuario
michi

Solo para que conste, aterricé desde Aquí Cómo corregir errores matemáticos al usar macros e intentaré expandir esta Respuesta aquí para que se ajuste a la Otra.

Usted está preguntando acerca de la diferencia acerca de:

#define Echo( a )  a
#define Echo( a ) ( a )

lo cual está bien siempre y cuando no entiendas la macro en sí misma (tampoco soy un experto :)).

En primer lugar, ya (probablemente) sabe que existe una precedencia de operadores, por lo que hay una gran diferencia entre estos dos programas:

1):

#include <stdio.h>
#define ADD( a , b ) a + b

int main( void )
{
    auto const int a = 5;
    auto const int b = 10;

    auto const int c = ADD (  2 + a ,  2 + b );
    printf( "%d", c );
    return 0;
}

Producción:

19

y:

#include <stdio.h>
#define ADD( a , b ) ( a ) + ( b )

int main( void )
{
    auto const int a = 5;
    auto const int b = 10;

    auto const int c = ADD ( a , b );
    printf( "%d", c );
    return 0;
}

Producción:

15

Ahora vamos a reemplazar + con *:

#define ADD( a, b ) a * b

El compilador trata a * b como por ejemplo a == 5 y b == 10 que hace 5 * 10.

Pero, cuando dices:
ADD ( 2 + a * 5 + b )
Como aquí:

#include <stdio.h>
#define ADD( a , b ) ( a ) * ( b )

int main( void )
{
    auto const int a = 5;
    auto const int b = 10;

    auto const int c = ADD ( 2 + a , 5 + b );
    printf( "%d", c );
    return 0;
}

Usted obtiene 105porque la precedencia del operador está involucrada y trata

2 + b * 5 + a

como

( 2 + 5 ) * ( 5 + 10 )

cual es

( 7 ) * ( 15 ) == 105

Pero cuando lo haces:

#include <stdio.h>
#define ADD( a, b ) a * b

int main( void )
{
    auto const int a = 5;
    auto const int b = 10;

    auto const int c = ADD ( 2 + a , 5 + b );
    printf( "%d", c );
    return 0;
}

usted obtiene 37 porque

 2 + 5 * 5 + 10

lo que significa:

2 + ( 5 * 5 ) + 10

lo que significa:

2 + 25 + 10

Respuesta corta, hay una gran diferencia entre:

#define ADD( a , b ) a * b

y

#define ADD( a , b ) ( a ) * ( a )

  • porque escribes auto antes de las variables? es totalmente redundante

    – Erik W.

    10 de febrero de 2018 a las 17:32

  • @ErikW Por favor, explícame qué es exactamente lo que encuentras mal al usar auto en estos ejemplos?

    – Michi

    10 de febrero de 2018 a las 17:43

  • Nunca necesitas escribir auto en C ya que todas las variables son automáticas cuando se declaran en el alcance (excepto cuando se declaran como explícitas static). No está mal, pero es innecesario.

    – Erik W.

    10 de febrero de 2018 a las 21:18


  • @ErikW No puedo responder a su pregunta siempre que no considere que el uso de auto en C es incorrecto.

    – Michi

    10 de febrero de 2018 a las 22:04

  • Probablemente sería la misma pregunta: ¿por qué la gente no usa return en main? ¿Solo porque está implícito desde el 99?

    – Michi

    10 de febrero de 2018 a las 22:17

¿Ha sido útil esta solución?