2009-05-05 1 views
15
int main() 
{ 
    int var = 0;; // Typo which compiles just fine 
} 
+33

Perché dovrebbero essere illegale? È come rendere illegale una riga vuota in VB. – dreamlax

+1

Non è possibile confrontare le regole di due lingue completamente diverse per convalidare una specifica scelta di linguaggio. – sharkin

+4

Il punto di Dreamlax (credo) è: qual è il danno? –

risposta

13

Questo è il modo in cui C e C++ esprimono NOP.

+0

Che è di primaria importanza per i sistemi di microcontrollori a budget limitato. – jpinto3912

+22

@ jpinto3912: Infatti ';' sarà quasi certamente compilato in * senza istruzioni *, piuttosto che nelle istruzioni 'NOP' della piattaforma di destinazione. –

+0

Ne dubito. Più probabile che sia un intrinseco, o asm. Nessuna istruzione! = NOP. – Nick

8

Non sono un designer di lingue, ma la risposta che darei è "perché no?" Dal punto di vista della progettazione linguistica, si desidera che le regole (ad esempio la grammatica) siano il più semplici possibile.

Senza contare che le espressioni "vuoti" hanno usi, cioè

for (i = 0; i < INSANE_NUMBER; i ++);

Will dead-wait (non è un buon uso, ma un uso comunque).

MODIFICA: come indicato in un commento a questa risposta, qualsiasi compilatore che meriti il ​​suo contenuto probabilmente non è occupato da attendere questo ciclo e ottimizzarlo. Tuttavia, se ci fosse qualcosa di più utile nella testa stessa (diversa da i ++), che ho visto fare (stranamente) con attraversamento della struttura dei dati, allora immagino che potresti ancora costruire un ciclo con un corpo vuoto (usando/abusando del costrutto "per").

+3

Sarà davvero aspettare? Il compilatore può ottimizzare il ciclo in quanto non succede niente? – Tom

+0

Buona domanda. Ora che me lo dici, non lo so. Tutto quello che so è che * dovrebbe *. :) –

+0

@ Tom: buona domanda. Almeno in C++, secondo lo standard, il tempo di esecuzione non è esplicitamente parte del "comportamento osservabile" del sistema, quindi in teoria suppongo che un compilatore possa ottimizzarlo. Tuttavia, se sono volatile, questa ottimizzazione è vietata. –

3

Il caso più comune è probabilmente

int i = 0; 
for (/* empty*/; i != 10; ++i) { 
    if (x[i].bad) break; 
} 
if (i != 10) { 
    /* panic */ 
} 
0
while(1){ 
    ; /* do nothing */ 
} 

Ci sono momenti in cui si vuole sedersi e non fare nulla. Un'applicazione incorporata basata su eventi/interrupt o quando non si desidera che una funzione esca come quando si impostano i thread e si attende il primo switch di contesto.

esempio: http://lxr.linux.no/linux+v2.6.29/arch/m68k/mac/misc.c#L523

+7

Test di raffreddamento della CPU? –

+6

Non è necessario il punto e virgola lì! –

+0

usato di solito in sparatorie di riferimento tra le lingue :) – gbjbaanb

10

E 'ovviamente in modo che possiamo dire le cose come

for(;;) { 
    // stuff 
} 

Chi potrebbe vivere senza questo?

+1

Dio non voglia che usiamo goto! –

+8

Questo non è un buon esempio, perché, ad esempio, il secondo punto e virgola non viene utilizzato per terminare un'istruzione. La seconda clausola del for è un'espressione; e lasciare che vuoto è trattato come un caso speciale che lo rende equivalente al vero. – newacct

+0

La domanda originale riguardava espressioni, non affermazioni. –

6

Sinceramente non so se questo è il vero motivo, ma penso che qualcosa che abbia più senso sia pensarlo dal punto di vista di un implementatore di compilatori.

Grandi porzioni di compilatori sono creati da strumenti automatici che analizzano classi speciali di grammatiche. Sembra molto naturale che le grammatiche utili consentano dichiarazioni vuote. Sembra un lavoro inutile per rilevare un tale "errore" quando non cambia la semantica del codice. L'istruzione vuota non farà nulla, in quanto il compilatore non genererà il codice per quelle istruzioni.

Mi sembra che questo è solo un risultato di "Non fissare qualcosa che non è rotto" ...

+0

Il compilatore C originale di DMR (da cui proviene questa sintassi) era un compilatore di discesa ricorsivo - tali compilatori sono normalmente scritti a mano, quindi non credo che i testicoli fossero un problema qui. –

+0

Questo sembra quasi * più probabile * che questo genere di cose accadrebbe. Se stai manipolando a mano un rdp, allora stai scrivendo una funzione per ogni produzione nella tua grammatica il cui compito è quello di far corrispondere il prossimo tratto di input ... Se le espressioni e altre cose costituiscono dichiarazioni, e sia le espressioni che altre cose possono finire non consumando input (tranne per il punto e virgola finale da seguire), quindi il parser riconoscerebbe tali affermazioni. Idk se questa è la vera ragione, ma sembra un modo ragionevole per risolverlo. (Non ho mai scritto un grosso r.d.p., ma ne ho scritto uno prima). – Tom

+0

Sto cercando ora una particolare grammatica Yacc per un linguaggio simile a C, e l'istruzione vuota richiede una regola aggiuntiva, quindi il contrario sembra essere vero. Almeno con quella grammatica, per quella lingua, per quello strumento. –

31

Come altro potrebbe assert(foo == bar); compilare verso il basso per nulla quando NDEBUG è definito?

+0

+1 per l'unica spiegazione del suono qui. –

+3

Bene, ora mi sembra che lasciarlo compilare a qualcosa come '0' o' ((void) 0) 'probabilmente andrebbe bene, ma comunque ... –

+2

' do {} while (0) ' – curiousguy

5

si vuole essere in grado di fare cose come

while (fnorble(the_smurf) == FAILED) 
    ; 

e non

while (fnorble(the_smurf) == FAILED) 
    do_nothing_just_because_you_have_to_write_something_here(); 

Ma! Si prega di non scrivere la dichiarazione vuota sulla stessa linea, in questo modo:

while (fnorble(the_smurf) == FAILED); 

Questo è un ottimo modo per confondere il lettore, dal momento che è facile perdere il punto e virgola, e quindi pensare che la riga successiva è il corpo del ciclo. Ricorda: la programmazione riguarda davvero la comunicazione, non con il compilatore, ma con altre persone che leggeranno il tuo codice. (! O con te stesso, tre anni più tardi)

5

OK, aggiungerò questo per lo scenario peggiore che si può effettivamente utilizzare:

for (int yy = 0; yy < nHeight; ++yy) 
{ 
    for (int xx = 0; xx < nWidth; ++xx) 
    { 
     for (int vv = yy - 3; vv <= yy + 3; ++vv) 
     { 
      for (int uu = xx - 3; uu <= xx + 3; ++uu) 
      { 
       if (test(uu, vv)) 
       { 
        goto Next; 
       } 
      } 
     } 

    Next:; 
    } 
} 
+1

+1 per l'esempio utile: poiché le etichette goto devono avere un'istruzione dopo di esse, ma nella rara occasione che è necessario un goto, l'etichetta è spesso solo necessaria nella parte inferiore di un ciclo, quindi è necessaria un'istruzione NOP. Si può scagliare contro gotos, ma a volte è preferibile (e più leggibile) usare un goto per uscire da loop nidificati, piuttosto che avere variabili extra e istruzioni if ​​() per uscire da ciascun loop singolarmente. – Darren

2

Quando si utilizza ';' per favore anche essere consapevoli di una cosa. Questo è ok:

a ? b() : c(); 

Tuttavia questo non compilerà:

a ? b() : ; ; 
+2

Questo perché ';' non può sostituire * un'espressione *; solo per una * dichiarazione *. – namezero