2013-08-08 24 views
13

Dzisiaj przypadkowo odkryłem, że mój kompilator nie uskarża się na pisanie kodu wewnątrz instrukcji przełączania bez obudowy. (Narzekało to na brak instrukcji postępowania, ale po dodaniu jednego po kodzie, nie było aż tak ostrzeżenia, aby dać mi znać, że kod był bezużyteczny.)Przełączanie bez obudowy

Próbuję ustalić, czy istnieje cel, aby zezwolić na poniższy kod lub jeśli jest to jedna z tych rzeczy, w których "więcej pracy należy ograniczyć, więc jest to dozwolone".

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

Teraz wyprowadza "4" zgodnie z oczekiwaniami, gdy a == 4, i nigdy nie wysyła foo. Pytanie brzmi, czy istnieje jakiś (potencjalnie ezoteryczny, ale użyteczny) powód, aby zezwolić na oświadczenie przed pierwszym przypadkiem? Wiem na pewno, że nie wolno mi zadeklarować i zainicjować tam zmiennych.

(FWIW, ja testowałem to na kilku kompilatorów, a oni wszyscy uzyskując takie samo zachowanie. Co ciekawe, oni też nie wszystko zrobić wyjście ostrzeżenie.)

+2

Jaki to kompilator? – turnt

+0

Testowałem to zarówno na MSVC 2012 i GCC 4.8.1. – Shirik

+0

Hmm interesujące. Jedną z myśli, która przychodzi do głowy, nie jest zapisywanie wartości domyślnej: zamiast tego wystarczy napisać kod pod ostatnim przypadkiem. Ale to krzyczy potencjalnie zła praktyka :) –

Odpowiedz

8

Tak, zachowanie jest jak zaprojektowany w język i możesz dodać kod w różnych miejscach. Instrukcje przełączników są znacznie bardziej skomplikowane niż wygląd i pozwalają na dość ezoteryczny kod, niezależnie od tego, czy ma to sens, czy nie.

Jeśli chcesz spędzić trochę czasu patrząc na dziwne zastosowania switch i lokalizację przypadków, możesz spojrzeć na implementację coroutines w bibliotece asio boost. Możesz napisać małą funkcję za pomocą makr, skompilować i zobaczyć jak wygląda wygenerowany kod (po rozszerzeniu makra).

+0

Realizacja boostu generalnie mnie przeraża, ale teraz wzbudziłeś moją ciekawość. – Shirik

+4

@Shirik kanonicznym przykładem czarnoksięstwa przełączającego jest [urządzenie Duffa] (http://en.wikipedia.org/wiki/Duff's_device): przełącznik spleciony z do-while. – TemplateRex

+0

Ninja'd. Cieszę się, że ktoś wspomniał o Urządzeniu Duffa. Ja (rzadko) używam tego rodzaju kreacji w systemach wbudowanych, aby rozbijać długie funkcje i ułatwić ich ponowne uruchamianie. Ale jeśli czujesz się brudny, kiedy używasz "goto", prawdopodobnie powinieneś pomyśleć o dodatkowej twardości przed użyciem przełączników dla tego rodzaju punktu wejścia. – Speed8ump

3

Z MSDN: -

Deklaracje mogą pojawić się na czele zestawienia związek tworzący korpusu przełącznika, ale pliki uruchamiania zawarte w deklaracji są nie wykonano. Instrukcja switch przekazuje kontrolę bezpośrednio do instrukcji wykonywalnej w ciele, omijając linie, które zawierają inicjalizacje .

+3

Nie nazwałbym MSDN * źródłem *, jeśli cokolwiek standardem byłby * THE * source. –

+0

Tak, przyjrzałem się standardowi C++, ale nie zaszedłem daleko. Wszystko co zrobiłem, to udowodnić sobie, że nic nie ogranicza tego. Jest to jeden z tych "dozwolonych z powodu braku reguły". – Shirik

+0

@MadScienceDreams: Jest to nielegalne, ponieważ inicjalizacja x jest ominięta przez instrukcję case. – Shirik