2014-12-20 12 views
25

Sto facendo alcuni esperimenti con la nuova parola chiave _Generic e sono incappato in un caso speciale riguardante più valutazioni. Vedere i seguenti:Effetti collaterali nelle espressioni generiche

#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'); 
} 

Questo compila bene e produce il risultato atteso con GCC:

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

D'altra parte, Clang emette un avvertimento grande clacson:

$ 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) 

... 

Eppure il il risultato è come previsto:

$ ./plusplus 
foo 

Ho controllato the draft of the standard, che dice (a pag. 97 del PDF):

L'espressione di controllo di una selezione generica non viene valutata.

Questo sembra indirizzare con precisione il problema degli effetti collaterali a macro (ad esempio, MIN e MAX).

Ora, posso ignorare tranquillamente l'avviso di Clang o mi sbaglio?

+5

Suona come si dovrebbe essere segnalando un problema al team di sviluppo Clang, piuttosto che ignorarlo. Potresti essere il primo ad aver riscontrato il problema. Cosa succede quando scrivi 'putchar (* s ++)'? Questo genera anche l'avviso? Presumibilmente no. –

+3

Penso che tu abbia scoperto un bug in clang! – haccks

+0

I fan di '_Generic' potrebbero essere vagamente ricordati di questa domanda, quindi ci collegherò qui e potranno decidere se è correlato (non penso che lo sia): http://stackoverflow.com/questions/24743520/incompatible-pointer-types-passing-in-generic-macro/ –

risposta

3

Come ho menzionato nei commenti, hai postato la domanda circa due settimane dopo che il bug è stato corretto nel trunk Clangs. Vedere la revisione rL223266 (3 dicembre 2014). La correzione è inclusa in Clang 3.6.

Ora, posso ignorare tranquillamente l'avviso di Clang o mi sbaglio?

Sappiamo già che tu abbia ragione, ecco un modo per ignorare pragma in Clang per la futuro:

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

write_char(*s++); 

#pragma clang diagnostic pop 

Per non ripetere su ogni utilizzo della macro, è potrebbe mettere _Pragma nel suo corpo:

#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") 
0

Sembra che fosse un bug. Ora è stato risolto dal clang 3.6 in poi come mostrato here.

Problemi correlati