Efectos secundarios en expresiones genéricas


Estoy haciendo algunos experimentos con la nueva palabra clave _Generic y me topé con un caso especial con respecto a múltiples evaluaciones. Véase lo siguiente:

#include <stdio.h>

#define write_char(c) _Generic(c, char: putchar, const char: putchar)(c)

int main(void)
{
    const char *s = "foo";

    write_char(*s++);
    write_char(*s++);
    write_char(*s++);

    putchar('\n');
}

Esto compila bien y produce el resultado esperado con GCC:

$ gcc -std=c11 -Wall plusplus.c -o plusplus
$ ./plusplus 
foo

Por otro lado, Clang produce una gran advertencia de bocina:

$ clang -std=c11 plusplus.c -o plusplus
plusplus.c:9:18: warning: multiple unsequenced modifications to 's'
      [-Wunsequenced]
    write_char(*s++);
                 ^~
plusplus.c:3:32: note: expanded from macro 'write_char'
#define write_char(c) _Generic(c, char: putchar, const char: putchar)(c)

...

Sin embargo, el resultado es el esperado:

$ ./plusplus
foo

Revisé el borrador de la norma, que dice (en la página 97 del PDF):

La expresión controladora de una selección genérica no se evalúa.

Esto parece abordar precisamente el problema de los efectos secundarios en las macros (por ejemplo, MIN y MAX).

Ahora, ¿puedo ignorar con seguridad la advertencia de Clang, o estoy equivocado?

Author: michaelmeyer, 2014-12-20

2 answers

Como mencioné en los comentarios, publicaste la pregunta unas dos semanas después de que se corrigiera el error en el tronco de Clangs. Véase la revisión rL223266 (3 de diciembre de 2014). La solución está incluida en Clang 3.6.

Ahora, ¿puedo ignorar con seguridad la advertencia de Clang, o estoy equivocado?

Ya sabemos que tienes razón, así que aquí hay una manera de ignorar pragmas in Clang para el futuro:

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunsequenced"

write_char(*s++);

#pragma clang diagnostic pop

Para no repetir en cada uso de la macro, podría poner _Pragma en su cuerpo:

#define write_char(c) \
    _Pragma("clang diagnostic push") \
    _Pragma("clang diagnostic ignored \"-Wunsequenced\"") \
    _Generic(c, char: putchar, const char: putchar)(c) \
    _Pragma("clang diagnostic pop")
 3
Author: xaizek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-03-05 17:44:33

Parece que fue un error. Ahora se ha resuelto desde clang 3.6 en adelante como se muestra aquí.

 0
Author: edmz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-03-05 15:57:45