2013-08-08 6 views
13

Oggi ho scoperto per caso che il mio compilatore non si lamenta quando scrive codice all'interno di un'istruzione switch senza un caso. (Si lamentava della mancanza di dichiarazioni di casi, ma dopo aver aggiunto uno dopo il codice, non c'era nemmeno un avvertimento per farmi sapere che il codice era inutile.)Switch senza custodia

Sto cercando di capire se c'è uno scopo per consentire il seguente codice, o se è solo una di quelle cose in cui "è più lavoro limitarlo, quindi è permesso".

#include <iostream> 
void foo() { 
    std::cout << "foo" << std::endl; 
} 

int main() 
{ 
    for (int a = -10; a < 10; ++a) 
    { 
     switch(a) 
     { 
     foo(); 
     case 4: 
     std::cout << "4" << std::endl; 
     } 
    } 
} 

Emette ora "4" come previsto quando un == 4, e non è mai uscite foo. Quindi la domanda è, c'è qualche motivo (potenzialmente esoterico ma utile) per consentire l'affermazione foo(); prima del primo caso? So per certo che non sono autorizzato a dichiarare e inizializzare le variabili lì.

(FWIW, ho provato questo su diversi compilatori, e sono tutti cedendo lo stesso comportamento. Sorprendentemente, anche tutti non lo fanno emettere un avvertimento.)

+2

Che compilatore è questo? – turnt

+0

L'ho provato su MSVC 2012 e GCC 4.8.1. – Shirik

+0

Hmm interessante. Un pensiero che viene in mente non è dover scrivere un default: e invece basta scrivere il codice sotto l'ultimo caso. Ma questo urla una potenziale cattiva pratica :) –

risposta

8

Sì, il comportamento è come previsto in la lingua e puoi aggiungere codice in posti diversi. Le istruzioni switch sono molto più complicate rispetto all'aspetto e consentono un codice piuttosto esoterico, indipendentemente dal fatto che abbia senso o meno.

Se si desidera passare un po 'di tempo a guardare alcuni usi strani di switch e la posizione dei casi, è possibile esaminare l'implementazione delle coroutine nella libreria boost asio. Puoi scrivere una piccola funzione con le macro, compilare e vedere come appare il codice generato (dopo l'espansione della macro).

+0

Generalmente l'implementazione del boost mi spaventa, ma ora hai stuzzicato la mia curiosità. – Shirik

+4

@Shirik l'esempio canonico di commutazione-stregoneria è [dispositivo di Duff] (http://en.wikipedia.org/wiki/Duff's_device): un interruttore intrecciato a un do-while. – TemplateRex

+0

Ninja'd. Sono felice che qualcuno abbia menzionato il dispositivo di Duff. Io (raramente) uso questo tipo di magia su sistemi embedded per suddividere funzioni lunghe e renderle più facili da riavviare. Ma, se ti senti sporco quando usi 'goto', dovresti probabilmente pensare molto prima di usare gli switch per questo tipo di entry point. – Speed8ump

3

Dalle MSDN: -

dichiarazioni possano apparire alla testa dello stato composto formatore corpo dell'interruttore, ma inizializzazioni incluse nelle dichiarazioni sono non eseguito. L'istruzione switch trasferisce il controllo direttamente a un'istruzione eseguibile all'interno del corpo, ignorando le righe che contengono le inizializzazioni .

+3

Non chiamerei MSDN * la fonte *, semmai lo standard sarebbe * LA * fonte. –

+0

Sì, ho dato uno sguardo allo standard C++, ma non sono andato molto lontano. Tutto quello che ho fatto è stato dimostrare a me stesso che non sembra esserci nulla che lo limiti. È più di una di quelle cose "permesse a causa della mancanza di una regola". – Shirik

+0

@MadScienceDreams: Questo è illegale perché l'inizializzazione di x è ignorata dall'istruzione case. – Shirik