2015-03-11 11 views
16

Durante la risposta al post this, ho suggerito di utilizzare do {...} while(0) per macro multilinea.è `warning C4127` (l'espressione condizionale è costante) sempre utile?

Su MSVC, ho trovato questo codice getta in su:

warning C4127: conditional expression is constant 

per rendere il codice di allarme-libera, ho bisogno di scegliere una di queste brutte alternative:

Opzione 1

#ifdef _MSC_VER 
#pragma warning(push) 
#pragma warning(disable:4127) 
#endif 
code_using_macro_that_generates_C4217; 
#ifdef _MSC_VER 
#pragma warning(pop) 
#endif 

Opzione 2
definire il mio macro come:

#define MULTI_LINE_MACRO do { ... } while(0,0) 

o

#define MULTI_LINE_MACRO do { ... } while((void)0,0) 

chiamato anche "civetta" da alcuni programmatori come (0,0) sembra un gufo.

Opzione 3
definire un nuovo WHILE_0 macro che non genera un messaggio di avviso e utilizzarlo al posto di while(0)

Problema
Credo che tutte le alternative sono più o meno orribile. Perché MSVC genera questo avviso per codice apparentemente corretto e mi motiva ad aggiungere un po 'di bruttezza al mio codice per mantenere libero il codice di avviso?

Credo che le espressioni costanti in condizionali siano perfettamente valide e utili, in particolare nei costrutti basati sulla capacità del compilatore di ottimizzare il codice.

Inoltre non ottengo un warning C4127 per codice come questo:

void foo(unsigned bar) 
{ 
    while (bar >= 0) 
     ; 
} 

La mia domanda è: non è warning C4127: conditional expression is constant completamente inutile e non è vero motivare codice brutto? Questo avvertimento aiuta sempre a scrivere un codice migliore?

+8

@Bathsheba: ma 'for (;;)' non ha lo stesso significato di 'fare {' '...} while (0)' !!!! –

+1

Bene se MSVC supporta C11 (* che non *), l'avviso non avrebbe molto senso dal momento che C11 ha un'eccezione specifica per [espressioni costanti come espressione di controllo per impedire l'ottimizzazione di loop infiniti] (http: // stackoverflow.it/a/28681034/1708801) Mi rendo conto che questo è il caso opposto, ma vale comunque. –

+6

Rimuovi il 'pragma' e [#include" no_sillywarnings_please.h "] (https://alfps.wordpress.com/the-no_sillywarnings_please-h-file/) –

risposta

5

Io non credo che sia mai utile. Al contrario, ci sono più falsi positivi rispetto al solo linguaggio do .. while(0). Pensate di costrutti come

if(sizeof(long) == 8) { /* ... */ } 
if(SOME_CONSTANT_MACRO) { /* ... */ } 

Il primo non può essere sostituito da #if direttive, quest'ultimo potrebbe, ma alcune linee guida dello stile di codifica preferire la versione if come il controllo della sintassi è ancora fatto per il codice morti (che non è morto altre piattaforme o con altre configurazioni in fase di compilazione) e alcuni lo trovano più piacevole da leggere.

Gli avvertimenti (diversi da quelli richiesti dallo standard, la maggior parte dei quali devono essere considerati come errori) vengono solitamente emessi per codice valido ma che potrebbe fare qualcos'altro rispetto a quanto previsto. if(0) o cose del genere questo sguardo stupido, ma non guardare, come se qualcosa di diverso da "controllo della sintassi di questo codice altrimenti morto" era destinato. Potrebbe ingannare il lettore, ma non è ambiguo, e non vedo come questo possa accadere accidentalmente.

Dagli esempi forniti finora (non ho MSVC da testare da solo), sembra che l'avviso sia per espressioni costanti nel senso del linguaggio C (cioè, non qualcosa che può essere costante -foldato ma sintatticamente non è un'espressione costante), quindi non viene emesso per if(array) o if(function) (ad esempio, ad esempio, gcc -Wall avvisa perché è probabile che si tratti di una chiamata di funzione).

while(0,0) è peggiore, a mio parere, si innesca un avviso con gcc -Wall per una parte sinistra di un operatore virgola, senza effetti collaterali, un avvertimento posso immaginare di essere di tanto in tanto utile (e che di solito è facile da evitare). Questo avviso scompare con while((void)0,0).

suggerisco girando l'avvertimento off.

3

Un avviso che un'espressione condizionale è costante sicuramente può essere utile. In molti casi, può indicare un errore logico nel codice.

Ad esempio, se si scrive qualcosa di simile:

if (x != NULL) { /* ... */ } 

dove x è un oggetto array, l'espressione è valida, ma l'espressione x decade in un puntatore al primo elemento dell'array, che non può essere un puntatore nullo. Non so se questo produce lo stesso errore, ma è un esempio dello stesso genere di cose.

Ovviamente non è sempre utile.Nel tuo caso, l'idioma

do { /* ... */ } while (0) 

è il modo migliore per scrivere una definizione di macro che è destinato ad essere utilizzato in un contesto che richiede una dichiarazione. L'utilizzo di while (0) in un altro contesto è probabilmente un errore logico [*].

'un peccato che il compilatore non lo riconosce come un idioma comune. Generare buoni avvisi è difficile; il compilatore deve andare oltre le regole del linguaggio e dedurre l'intento del programmatore.

In questo caso, utilizzando un metodo specifico per il compilatore per eliminare l'avviso (a patto che non si rompe il codice per altri compilatori) è probabilmente l'approccio migliore. L'utilizzo di un'opzione della riga di comando per sopprimere l'avviso in tutti i casi sarebbe eccessivo; potresti perdere avvisi validi in altre parti del tuo codice.

Apparentemente scrivere while (0,0) anziché while (0) evita l'avviso. Se lo fai, dovresti aggiungere un commento che indichi chiaramente che è una soluzione alternativa per il tuo particolare compilatore. Non c'è alcun motivo particolare per cui un compilatore non dovrebbe avvisare su while (0,0) o qualsiasi altro codice equivalente.

[*] Si può dare un senso a scrivere una dichiarazione do { /* ... */ } while (0) se si vuole essere in grado di utilizzare break per saltare fuori di esso.

+3

Dagli esempi forniti finora, sembra che l'avviso sia stato attivato solo per le espressioni costanti (non per i costrutti non costanti che possono essere piegati in modo costante), quindi non viene emesso per 'if (x! = NULL)'. Altrimenti, perché non è attivato per 'if (0,0)'? – mafso