La necesidad de paréntesis en macros en C [duplicate]

3 minutos de lectura

avatar de usuario
Kushal

Intenté jugar con la definición de la macro. SQR en el siguiente código:

#define SQR(x) (x*x)
int main()
{
    int a, b=3;
    a = SQR(b+5);      // Ideally should be replaced with (3+5*5+3), though not sure.
    printf("%d\n",a);
    return 0;
}

se imprime 23. Si cambio la definición de macro a SQR(x) ((x)*(x)) entonces la salida es la esperada, 64. Sé que una llamada a una macro en C reemplaza la llamada con la definición de la macro, pero todavía no puedo entender cómo se calculó. 23.

  • En tu futura carrera. Trate de no confiar en las macros en absoluto. O si tiene que usarlos, utilícelos para fragmentos de código muy pequeños. No grandes monstruosidades macro que cubren media página.

    – C. Johnson

    30 mayo 2012 a las 16:30


  • @CJohnson: Sí, apenas me he dado cuenta de la necesidad de usar una Macro en mis proyectos de C/C++, esta es una de esas áreas confusas de C, incluso después de haber sido desarrollador/estudiante durante años.

    – Kushal

    30 de mayo de 2012 a las 16:42

  • Relacionado: ¿Podemos eliminar los paréntesis alrededor de los argumentos en las definiciones de macros de C?

    – Palec

    29 de abril de 2015 a las 8:51

  • Relacionado: ¿Cuándo se pueden omitir los paréntesis alrededor de los argumentos en las macros?

    – Palec

    29 de abril de 2015 a las 9:43

  • Buena respuesta a un duplicado.

    – Palec

    29 de abril de 2015 a las 9:58

avatar de usuario
pb2q

Considere el reemplazo de macro usando esta macro:

#define SQR(x) (x*x)

Utilizando b+5 como el argumento. Realice el reemplazo usted mismo. En tu código, SQR(b+5) se convertirá: (b+5*b+5)o (3+5*3+5). Ahora recuerda tu precedencia del operador normas: * antes de +. Entonces esto se evalúa como: (3+15+5)o 23.

La segunda versión de la macro:

#define SQR(x) ((x) * (x))

Es correcto, porque está utilizando los paréntesis para proteger sus argumentos macro de los efectos de la precedencia del operador.

Esta página explicar la preferencia del operador por C tiene un buen gráfico. Aquí está la sección correspondiente del documento de referencia C11.

Lo que debe recordar aquí es que debe adquirir el hábito de proteger siempre cualquier argumento en sus macros, usando paréntesis.

Porque (3+5*3+5 == 23).

Mientras ((3+5)*(3+5)) == 64.

La mejor manera de hacer esto es no usar una macro:

inline int SQR(int x) { return x*x; }

O simplemente escribe x*x.

avatar de usuario
Estera

La macro se expande a

 a = b+5*b+5;

es decir

 a = b + (5*b) + 5;

Entonces 23.

Después del preprocesamiento, SQR(b+5) se ampliará a (b+5*b+5). Esto obviamente no es correcto.

Hay dos errores comunes en la definición de SQR:

  1. no encierre argumentos de macro entre paréntesis en el cuerpo de la macro, por lo que si esos argumentos son expresiones, los operadores con diferentes precedencias en esas expresiones pueden causar problemas. Aquí hay una versión que solucionó este problema.

    #define SQR(x) ((x)*(x))
    
  2. evaluar argumentos de macro más de una vez, por lo que si esos argumentos son expresiones que tienen efectos secundarios, esos efectos secundarios podrían tomarse más de una vez. Por ejemplo, considere el resultado de SQR(++x).

    Mediante el uso de CCG tipo de extensión, este problema se puede arreglar así

    #define SQR(x) ({ typeof (x) _x = (x); _x * _x; })
    

Ambos problemas podrían solucionarse reemplazando esa macro con una función en línea

   inline int SQR(x) { return x * x; }

Esto requiere la extensión en línea GCC o C99, consulte 6.40 Una función en línea es tan rápida como una macro.

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad