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

A menudo, y con frecuencia, sentí que algunos de los paréntesis en torno a los argumentos en las definiciones de macros eran redundantes. Es demasiado incómodo parénselo todo. Si puedo garantizar que el argumento no tiene que estar entre paréntesis, ¿puedo omitir los paréntesis? ¿O es altamente recomendable paréntesis a todos ellos?

Se me ocurrió esta pregunta cuando escribí:

#define SWAP_REAL(a, b, temp) do{double temp = a; a = b; b= temp;}while(0) 

Creo que si un argumento aparece como un valor l en la macro, los paréntesis se pueden omitir porque eso significa que el argumento aparece sin ninguna otra operación.

Mi razonamiento es:

  1. La prioridad asociativa de los símbolos de asignación es simplemente más alta que la de coma.
  2. No puede confundir al comstackdor para que piense que su argumento es una expresión con una coma. Por ejemplo, SWAP(a, b, b) no se interpretará correctamente como

     do{double temp = a, b; a, b = b; b= temp;}while(0) 

    Que puede pasar la comstackción.

Estoy en lo cierto ¿Alguien puede darme un contra-ejemplo?

En el siguiente ejemplo,

 #define ADD(a, b) (a += (b)) 

Creo que el argumento no tiene que estar entre paréntesis. Y en este caso específico, ninguno necesita el argumento b , ¿verdad?

@JaredPar:

  #include  #define ADD(a, b) (a += (b)) int main(){ int a = 0, b = 1; ADD(a; b, 2); return 0; } 

Esto no se puede comstackr con éxito en mi VS2010. Error C2143: syntax error : missing ')' before ';'


En pocas palabras, no necesita paréntesis de los argumentos que aparecieron como un valor l en la macro, pero se recomienda encarecidamente paréntesis de todos ellos.

Reglas de macros:

  1. ¡NO hagas macros con efectos secundarios!
  2. En cuanto a las macros sin efectos secundarios, ¡simplemente paréntesis de todos los argumentos sin pensarlo dos veces!
  3. En cuanto a las macros con efecto secundario, ¡deja de ser obsesivo! ¡Paréntesis a todos! TnT

No es seguro omitir si usas cualquier operador que no tenga la prioridad más baja en tu expresión. Creo que eso sería una coma.

a op b donde op es algún operador como + , * etc. siempre se unirá mal si a contiene una expresión de baja precedencia como 1 || 2 1 || 2 .

Tenga en cuenta que no estoy diciendo que sea seguro en esos casos. Hay formas más creativas de romper macros. Por cierto, no uses macros con efectos secundarios en primer lugar. Más generalmente, no use macros como funciones. (Ver, por ejemplo, Efectivo C ++).

Aquí hay un caso donde hace una diferencia demostrable

 ADD(x;y, 42) 

Con parens esto conduce a un error de comstackción, pero sin él conduce al código que comstack.

 (x;y) += 42; // With parens errors x;y += 42; // Without parens compiles 

Esto puede parecer un ejemplo tonto, pero es posible que la combinación de macros pueda llevar fácilmente a expresiones de código extrañas como la anterior.

¿Por qué arriesgarte aquí? Son solo 2 personajes

Hay macros en las que está concatenando elementos para crear una cadena (tal vez utilizando el operador # ), o creando identificadores a partir de argumentos de macro utilizando el operador ## . En tales casos, no paréntesis los argumentos.

Además, creo que cuando los argumentos de la macro se pasan a sí mismos como argumentos de la función, entonces no es absolutamente necesario paréntesis:

 #define CALLOC(s, n) calloc(s, n) 

Puedes jugar a juegos diabólicos llamando a una macro de este tipo ( CALLOC({3, 4}) ), pero obtienes lo que mereces (un error de comstackción). No tengo conocimiento de una forma de llamar a esa macro que funcionaría si en lugar de la macro que escribió los mismos argumentos que una llamada directa a calloc() .

Sin embargo, si está utilizando los argumentos en la mayoría de las expresiones aritméticas, entonces necesita envolverlos entre paréntesis:

 #define MIN(x, y) (((x) < (y)) ? (x) : (y)) 

Obviamente, si lo invocas con argumentos con efectos secundarios, obtendrás lo que obtienes. Pero los argumentos no se malinterpretarán como podrían ser si escribieras:

 #define MIN(x, y) x < y ? x : y 

y luego lo invocó como:

 MIN(x = 3 * y + 1, y = 2 * x - 2); 

El comentario de Moon sugiere una macro SWAP_INT .

El siguiente código que utiliza esa macro comstack limpiamente cuando se comstack con las opciones predeterminadas, pero no se comstack con el conjunto -DWITH_PARENTHESES .

 #include  #ifdef WITH_PARENTHESES #define SWAP_INT(a, b) do { int temp = (a); (a) = (b); (b) = temp; } while (0) #else #define SWAP_INT(a, b) do { int temp = a; a = b; b = temp; } while (0) #endif int main(void) { int p = 319; int q = 9923; int x = 23; int y = 300; printf("p = %8d, q = %8d, x = %8d, y = %8d\n", p, q, x, y); SWAP_INT(p, q); // OK both ways SWAP_INT(x, y); // OK both ways printf("p = %8d, q = %8d, x = %8d, y = %8d\n", p, q, x, y); SWAP_INT(x /= y, p *= q); // Compiles without parentheses; fails with them printf("p = %8d, q = %8d, x = %8d, y = %8d\n", p, q, x, y); return 0; } 

La salida:

 p = 319, q = 9923, x = 23, y = 300 p = 9923, q = 319, x = 300, y = 23 p = 41150681, q = 13, x = 0, y = 3165437 

Esa no es una forma segura o efectiva de intercambiar enteros: la macro sin los paréntesis no es una buena idea.