Mam sytuację, w której chciałbym, aby dwa przypadki w instrukcji przełącznika C ++ przechodziły do trzeciego przypadku. W szczególności druga sprawa przechodziłaby do trzeciej sprawy, a pierwsza sprawa również przechodziłaby do trzeciej sprawy bez przechodzenia przez drugą sprawę.
Miałem głupi pomysł, wypróbowałem go i zadziałało! I owinięty drugi przypadek w if (0) {
... }
. To wygląda tak:
#ifdef __cplusplus
# include <cstdio>
#else
# include <stdio.h>
#endif
int main(void) {
for (int i = 0; i < 3; i++) {
printf("%d: ", i);
switch (i) {
case 0:
putchar('a');
// @fallthrough@
if (0) { // fall past all of case 1 (!)
case 1:
putchar('b');
// @fallthrough@
}
case 2:
putchar('c');
break;
}
putchar('\n');
}
return 0;
}
Po uruchomieniu otrzymuję żądany wynik:
0: ac
1: bc
2: c
Wypróbowałem to zarówno w C, jak i C ++ (oba z clang) i zrobiło to samo.
Moje pytania to: czy to jest poprawne C / C ++? Czy ma robić to, co robi?
c++
c
if-statement
switch-statement
language-lawyer
Mark Adler
źródło
źródło
switch(x) { case A: case B: do_this(); if(x == B) also_do_that(); ... }
. To też, IMO, było okropne. Proszę, po prostu wypisz takie rzeczy jak instrukcje, nawet jeśli oznacza to, że musisz powtórzyć jedną linię w dwóch miejscach. Używaj funkcji i zmiennych (i dokumentacji!), Aby zmniejszyć ryzyko przypadkowej późniejszej aktualizacji tylko w jednym miejscu.Odpowiedzi:
Tak, jest to dozwolone i robi to, co chcesz. W przypadku
switch
instrukcji standard C ++ mówi :Kiedy więc
if
instrukcja jest oceniana, przepływ sterowania przebiega zgodnie z regułamiif
instrukcji, niezależnie od występujących w nim etykiet przypadków.źródło
Tak, to powinno działać. Etykiety przypadków dla instrukcji switch w C są prawie identyczne z etykietami goto (z pewnymi zastrzeżeniami dotyczącymi ich działania z zagnieżdżonymi instrukcjami switch). W szczególności same nie definiują bloków dla instrukcji, o których myślisz, że są „wewnątrz sprawy” i możesz ich użyć, aby wskoczyć do środka bloku, tak jak w przypadku goto. Podczas przeskakiwania do środka bloku obowiązują te same zastrzeżenia, co w przypadku goto, dotyczące przeskakiwania inicjalizacji zmiennych itp.
Mając to na uwadze, w praktyce prawdopodobnie łatwiej jest napisać to za pomocą instrukcji goto, jak w:
switch (i) { case 0: putchar('a'); goto case2; case 1: putchar('b'); // @fallthrough@ case2: case 2: putchar('c'); break; }
źródło
bee
(w trybie C; w C ++ błąd „nie może przeskoczyć z instrukcji switch do tego przypadku etykieta / skok omija inicjalizację zmiennej”).goto
jest czystszym rozwiązaniem.goto
jest bardzo złośliwy, ale naprawdę nie ma w nim nic niewłaściwego, jeśli nie robisz z niego skomplikowanych struktur kontrolnych ręcznie. Cała „goto uważana za szkodliwą” dotyczyła pisania kodu HLL (np. C), który wygląda jak asm emitowany przez kompilator (jmps tam iz powrotem w każdym miejscu). Istnieje wiele dobrze zorganizowanych zastosowań goto, takich jak tylko do przodu (koncepcyjnie nie różni się odbreak
lub wczesnereturn
), mało prawdopodobne-powtórne tylko w pętli (pozwala uniknąć zasłaniania wspólnej ścieżki przepływu i kompensuje brak zagnieżdżonych-continue
) itp.Jak wspomniały inne odpowiedzi, jest to technicznie dozwolone przez standard, ale jest to bardzo zagmatwane i niejasne dla przyszłych czytelników kodu.
Dlatego
switch ... case
instrukcje powinny być zwykle pisane z wywołaniami funkcji, a nie z dużą ilością kodu wbudowanego.switch(i) { case 0: do_zero_case(); do_general_stuff(); break; case 1: do_one_case(); do_general_stuff(); break; case 2: do_general_stuff(); break; default: do_default_not_zero_not_one_not_general_stuff(); break; }
źródło
do_general_stuff
domyślny, tylko dla przypadku 2 (oraz 0 i 1).i
Jednak nigdy nie uruchamia przełącznika poza zakresem 0..2.do_general_stuff
domyślny, tylko dla przypadku 2 (oraz 0 i 1).general
idefault
były to różne słowa. OTOH, to znany fakt, że ludzie zazwyczaj nadal potrafią czytać słowo, jeśli środkowe litery są zaszyfrowane; mamy tendencję do patrzenia na początek i koniec, więc posiadanie innego tylko środka prawdopodobnie nie jest idealnym rozwiązaniem dla odtłuszczania. Być może usuńdo_
przedrostek.