2012-01-31 9 views
42

Chiaramente, ci sono momenti in cui define s devono avere parentesi, in questo modo:C'è una buona ragione per racchiudere sempre una definizione tra parentesi in C?

#define WIDTH 80+20 

int a = WIDTH * 2; //expect a==200 but a==120 

Così ho sempre tra parentesi, anche se è solo un numero singolo:

#define WIDTH (100) 

qualcuno nuovo C mi ha chiesto perché lo faccio, quindi ho cercato di trovare un caso limite in cui l'assenza di parentesi su un singolo numero define causasse problemi, ma non riesco a pensarne uno.

Esiste un caso del genere?

+0

mi limiterò a lasciare questo qui: http://www.parashift.com/c++-faq-lite/inline-functions. html # faq-9.5 (Cerca i collegamenti sul perché le macro di # define' sono malvagie). –

+0

@TReddy Grazie, ma non si sostituisce un '#define WIDTH (100)' con 'inline int width() {return 100; } vuoi ?! – weston

+0

No, volevo condividere i link sul perché le macro sono malvagie e quei collegamenti sono stati raccolti in quella sezione sulle funzioni inline (che è ortogonale alla tua domanda). Nella tua situazione, una macro ti dà risultati migliori di una 'static int width = 80 + 20'? –

risposta

32

. L'operatore di preprocessore di concatenazione (##) causerà problemi, ad esempio:

#define _add_penguin(a) penguin ## a 
#define add_penguin(a) _add_penguin(a) 

#define WIDTH (100) 
#define HEIGHT 200  

add_penguin(HEIGHT) // expands to penguin200 
add_penguin(WIDTH) // error, cannot concatenate penguin and (100) 

Lo stesso vale per stringization (#). Chiaramente questo è un caso d'angolo e probabilmente non importa considerando come sarà presumibilmente usato WIDTH. Eppure, è qualcosa da tenere a mente sul preprocessore.

(Il motivo per aggiungere il secondo pinguino non è un dettaglio sottile delle regole di pre-elaborazione in C99 - iirc si riesce perché concatenare due token di preelaborazione non placeholder deve sempre risultare in un singolo token preelaborazione - ma questo è irrilevante, anche se fosse concessa la concatenazione, avrebbe comunque dato un risultato diverso rispetto allo #define non presidiato!).

Tutte le altre risposte sono corrette solo nella misura in cui non ha importanza dal punto di vista dello scanner C++ perché, in effetti, un numero è atomico. Tuttavia, alla mia lettura della domanda non vi è alcun segno che solo i casi privi di ulteriore espansione del preprocessore debbano essere considerati, quindi le altre risposte sono, anche se sono completamente d'accordo con i consigli ivi contenuti, errate.

+1

Soluzione semplice: vietate il ## da tutto il vostro codice C, nel vostro standard di codifica. Ho codificato C per quasi 15 anni e non ho mai sentito il bisogno di usare ##. – Lundin

+0

In realtà, per me questo compila bene finché definisco una funzione 'penguin200' e' pinguino (int a) '. Sembra non avere problemi a concatenare il pinguino e (100) a formare 'pinguino (100)' che è chiamato con successo. Potrei comunque usare C89. – weston

+1

Sì, questo potrebbe essere dovuto a diverse specifiche del preprocessore ('gnu cpp' non riesce sul mio computer). Ma penso che siamo d'accordo che questo non è rilevante per la domanda ... –

5

Dal 100 è un unico token, dubito troverete un caso angolo dove le parentesi materia (per un solo simbolo!)

E 'ancora una buona abitudine IMO, dal momento che possono importa quando ci sono più token coinvolti.

6

Ogni volta che la definizione è costituita da un singolo token (un solo operando, nessun operatore), le parentesi non sono necessarie perché un singolo token (come 100) è un atomo indivisibile durante il lexing e l'analisi.

5

No. Non c'è alcun caso in cui lo #define WIDTH 100 possa produrre un'espansione non ambigua o "sorprendente". Questo perché può solo far sostituire un singolo token da un singolo token.

Come sapete, la confusione di macro deriva quando un singolo token (ad esempio WIDTH) genera più token (ad esempio 80 + 20). Per quanto posso supporre, questo è il solo causa per l'uso di parentesi nelle sostituzioni e, come esplorato nel mio primo paragrafo, non si applica qui.

Tuttavia, a parte questo fatto tecnico, potrebbe essere ancora una buona pratica. Promuove l'abitudine e serve anche come promemoria se quella macro viene modificata in qualcosa di più complesso.

3

C'è una buona ragione, a volte.

Per un numero singolo, non c'è una buona ragione.

In altri casi, come hai dimostrato, c'è una buona ragione.

Alcune persone preferiscono essere particolarmente attente e usano sempre le parentesi (lo raccomando @aix.) Non lo so, ma non c'è una risposta difficile.

+0

Grazie per la modifica, @Lightness. Mi rendo conto di aver sbagliato le parentesi in tutti questi anni ... – ugoren

+0

FYI il singolare è una parentesi. :) –

+0

Sì, l'ho appena controllato. Inoltre, l'intera faccenda (le parentesi più ciò che è in esse) è una parentesi (in inglese, non sono sicuro di C). – ugoren

1

Di certo non farà male ed è una buona abitudine. Ma non c'è differenza tra (100) e 100 per i calcoli numerici.

23

A volte è necessario scrivere il codice non con gli avvertimenti attuali in mente, ma con le avvertenze di la prossima volta che verrà modificato.

In questo momento la macro è un singolo numero intero. Immagina qualcuno che lo modifica in futuro. Diciamo che non sei tu, ma qualcuno che è meno attento o più di fretta. La parentesi è lì per ricordare loro di inserire le modifiche tra parentesi.

Questo tipo di pensiero è una buona abitudine in C.Personalmente, scrivo codice in uno stile che alcune persone potrebbero trovare "ridondante", con cose come questa, ma soprattutto per quanto riguarda la gestione degli errori. La ridondanza è per la manutenibilità e la componibilità delle modifiche future.

+1

+1: proprio quello che stavo scrivendo. – ChrisBD

+4

Se qualcuno sa che le macro non banali hanno bisogno di una parentesi, le aggiungerà quando cambierà. Altrimenti, creerà un disastro, qualunque cosa tu faccia. Quindi sono contrario all'aggiunta di parentesi che chiaramente non sono necessarie. Ma è una questione di opinione. – ugoren

+3

Non sono d'accordo: non dovresti preoccuparti della possibilità che i non programmatori mantengano il tuo codice in futuro. La parentesi attorno alle espressioni macro è una cosa così basilare, dovresti essere in grado di assumere che ogni programmatore C ne sia a conoscenza. Altrimenti, usando lo stesso argomento, dovresti mettere la parentesi attorno a _everything_: 'int x = y + z;' (non una macro) dovrebbe quindi con la stessa logica imperfetta essere sempre scritta come 'int x = (y + z);' , nel caso in cui un non programmatore stressato manterrà il codice in futuro, per ricordare loro i pericoli della precedenza degli operatori. – Lundin

6

Come Blagovest Buyukliev detto:

La definire costituito da un singolo token (solo operando, non operatori), le parentesi non sono necessari perché un singolo token (ad esempio 100) è un atomo indivisibile quando lexing e analisi.

Ma mi sento di raccomandare le seguenti regole quando si tratta di macro:

  1. funzione evitare come macro @see commento di Lundin.

Se si desidera utilizzare la funzione, come le macro considerano gravemente i seguenti 2 regole:

  1. utilizzare sempre staffe per argomenti nelle macro
  2. Utilizzare solo un argomento di macro una volta

Perché regola 1.? (Per mantenere l'ordine delle operazioni corrette)

#define quad(x) (x*x) 
int a = quad(2+3); 

si espanderà a:

int a = (2+3*2+3); 

Perché regola 2.? (Per garantire un effetto collaterale è applicata una sola volta)

#define quad(x) (x*x) 
int i = 1; 
int a = quad(i++); 

si espanderà per:

int a = i++ * i++; 
+1

Pensando a questo per un po ', una macro simile a una funzione potrebbe fare riferimento a una variabile nel contesto non argomento, mentre un inline non può. Ma come hai detto tu, non c'è una vera buona ragione per usare una cosa del genere. Ho fatto parte di una revisione molto ampia del codice presso un ex datore di lavoro, dove abbiamo finito per scrivere un sacco di inline, contro la politica di codifica aziendale, per sostituire tonnellate di codice replicato sparsi in tutta la nostra parte del sistema operativo che altrimenti sarebbe stato scritto come macro simili a funzioni. Abbiamo finito per passare dalla fonte numero 1 di bug ad essere un modello su come farlo nel modo giusto. –

+0

@Lundin un singolo caso è generico "funzioni" come 'max'. In C++ potresti implementarli come modelli multiparametrici.L'unica opzione veramente flessibile in C per questo è una macro simile a una funzione. – Ruslan

1

Quando codice definisce solo un numero, @Alexander Gessler risponde bene la domanda.

Tuttavia molti codificatori non notano i operatori unari nella seguente:

#define TEMPERATURE1M (-1) 
#define TEMPERATURE1P (+1) 

Quando il codice utilizza un #define che impiega un operatore, che racchiude () assicura risultati attesi numerici e precedenza.

#define TEMPERATURE_WITH (-1) 
#define TEMPERATURE_WITHOUT -1 

// Consider how these will compile 
int w = 10-TEMPERATURE_WITH; 
int wo = 10-TEMPERATURE_WITHOUT; // May not compile 

L'ultima riga di codice può compilare dato C99 cambiamenti semantici @Olaf

Problemi correlati