Durch einen kleinen Tippfehler habe ich versehentlich dieses Konstrukt gefunden:
int main(void) {
char foo = 'c';
switch(foo)
{
printf("Cant Touch This\n"); // This line is Unreachable
case 'a': printf("A\n"); break;
case 'b': printf("B\n"); break;
case 'c': printf("C\n"); break;
case 'd': printf("D\n"); break;
}
return 0;
}
Es scheint, dass die printf
oben in der switch
Aussage gültige, aber auch völlig unerreichbare ist.
Ich habe eine saubere Kompilierung erhalten, ohne auch nur eine Warnung vor nicht erreichbarem Code, aber das scheint sinnlos.
Sollte ein Compiler dies als nicht erreichbaren Code kennzeichnen?
Hat dies überhaupt einen Zweck?
c
switch-statement
language-lawyer
abelenky
quelle
quelle
-Wswitch-unreachable
goto
in den ansonsten nicht erreichbaren Teil ein- und aussteigen, was für verschiedene Hacks nützlich sein kann.switch
ist nur eine Bedingunggoto
mit mehreren Beschriftungen. Es gibt mehr oder weniger dieselben Einschränkungen für den Körper wie für einen normalen Codeblock, der mit goto-Labels gefüllt ist.Antworten:
Vielleicht nicht das Nützlichste, aber nicht völlig wertlos. Sie können es verwenden, um eine lokale Variable zu deklarieren, die innerhalb des
switch
Gültigkeitsbereichs verfügbar ist .Der Standard (
N1579 6.8.4.2/7
) hat das folgende Beispiel:PS Übrigens ist das Beispiel kein gültiger C ++ - Code. In diesem Fall (
N4140 6.7/3
Schwerpunkt meiner):Das Ersetzen
int i = 4;
durchint i;
macht es also zu einem gültigen C ++.quelle
i
es auf 4 initialisiert. Was fehlt mir?static
bei Null auf Null initialisiert wird, sodass auch hierfür eine sichere Verwendung besteht.i = 4;
Initialisierung, also findet sie nie statt.case
und musste immer unterschiedliche Namen verwendencase
oder sie außerhalb des Schalters definieren.Ja. Wenn Sie anstelle einer Aussage eine Erklärung vor das erste Etikett setzen, kann dies durchaus Sinn machen:
Die Regeln für Deklarationen und Anweisungen werden im Allgemeinen für Blöcke gemeinsam genutzt. Daher ist es dieselbe Regel, die dies zulässt, dass auch Anweisungen dort zulässig sind.
Erwähnenswert ist auch, dass, wenn die erste Anweisung ein Schleifenkonstrukt ist, Fallbezeichnungen im Schleifenkörper erscheinen können:
Bitte schreiben Sie keinen Code wie diesen, wenn es eine besser lesbare Schreibweise gibt, diese jedoch vollkommen gültig ist und der
f()
Anruf erreichbar ist.quelle
{ /*code*/ switch(x) { } }
sieht er möglicherweise sauberer aus, ist aber auch falsch .Es gibt eine berühmte Verwendung dieses Duff's Device .
Hier kopieren wir einen Puffer, auf den von gezeigt wird,
from
in einen Puffer, auf den von gezeigt wirdto
. Wir kopierencount
Dateninstanzen.Die
do{}while()
Anweisung beginnt vor dem erstencase
Label und diecase
Labels sind in das eingebettetdo{}while()
.Dies reduziert die Anzahl der bedingten Verzweigungen am Ende der
do{}while()
Schleife um ungefähr den Faktor 4 (in diesem Beispiel kann die Konstante auf den gewünschten Wert angepasst werden).Jetzt können Optimierer dies manchmal für Sie tun (insbesondere wenn sie Streaming- / vektorisierte Anweisungen optimieren), aber ohne profilgesteuerte Optimierung können sie nicht wissen, ob Sie erwarten, dass die Schleife groß ist oder nicht.
Im Allgemeinen können dort Variablendeklarationen auftreten, die in jedem Fall verwendet werden, aber nach dem Ende des Schalters außerhalb des Gültigkeitsbereichs liegen. (Beachten Sie, dass jede Initialisierung übersprungen wird.)
Darüber hinaus können Sie durch einen nicht schalterspezifischen Steuerungsfluss in diesen Abschnitt des Schaltblocks gelangen, wie oben dargestellt, oder mit einem
goto
.quelle
do {
undcase 0:
egal sind, beide dazu dienen, ein Sprungziel auf den ersten zu setzen*to = *from++;
.do {
ist besser lesbar. Ja, über die Lesbarkeit von Duffs Gerät zu streiten ist dumm und sinnlos und wahrscheinlich ein einfacher Weg, verrückt zu werden.Angenommen, Sie verwenden gcc unter Linux, hätte es Sie gewarnt, wenn Sie 4.4 oder eine frühere Version verwenden.
Die Option -Wunreachable-Code wurde ab gcc 4.4 entfernt .
quelle
Nicht nur für die Variablendeklaration, sondern auch für fortgeschrittenes Springen. Sie können es genau dann gut verwenden, wenn Sie nicht anfällig für Spaghetti-Code sind.
Druckt
Es ist zu beachten, dass der Schaltfall eine der schnellsten Kontrollflussklauseln ist. Daher muss es für den Programmierer sehr flexibel sein, was manchmal solche Fälle betrifft.
quelle
nocase:
unddefault:
?i=4
es nicht ausgelöst wirdnocase
.Es ist zu beachten, dass der Code in der
switch
Anweisung oder diecase *:
Position der Beschriftungen in diesem Code * praktisch keine strukturellen Einschränkungen aufweist . Dies ermöglicht Programmiertricks wie das Gerät von duff , von denen eine mögliche Implementierung folgendermaßen aussieht:Sie sehen, der Code zwischen dem
switch(n%8) {
und demcase 7:
Etikett ist definitiv erreichbar ...* Wie Supercat dankbar in einem Kommentar hervorhob : Seit C99 darf weder ein
goto
noch ein Etikett (sei es eincase *:
Etikett oder nicht) im Rahmen einer Erklärung erscheinen, die eine VLA-Erklärung enthält. Es ist also nicht richtig zu sagen, dass es keine strukturellen Einschränkungen bei der Platzierung dercase *:
Etiketten gibt. Das Gerät von duff ist jedoch älter als der C99-Standard und hängt sowieso nicht von den VLAs ab. Trotzdem fühlte ich mich gezwungen, aus diesem Grund ein "virtuelles" in meinen ersten Satz einzufügen.quelle
goto
noch eineswitch/case/default
Bezeichnung dürfen im Bereich eines variabel deklarierten Objekts oder Typs erscheinen. Dies bedeutet effektiv, dass Beschriftungen vor diesen Deklarationen stehen müssen, wenn ein Block Deklarationen von Array-Objekten oder -Typen variabler Länge enthält. Der Standard enthält eine verwirrende Redewendung, die darauf hindeutet, dass sich der Geltungsbereich einer VLA-Deklaration in einigen Fällen auf die Gesamtheit einer switch-Anweisung erstreckt. Siehe stackoverflow.com/questions/41752072/… für meine Frage dazu.Sie haben Ihre Antwort in Bezug auf die erforderliche
gcc
Option-Wswitch-unreachable
zum Generieren der Warnung erhalten. Diese Antwort dient dazu, den Teil Benutzerfreundlichkeit / Wertigkeit zu erläutern .Zitat direkt aus
C11
Kapitel §6.8.4.2 ( Hervorhebung von mir )Welches ist sehr selbsterklärend. Mit dieser Option können Sie eine Variable mit lokalem Gültigkeitsbereich definieren, die nur innerhalb des
switch
Anweisungsbereichs verfügbar ist .quelle
Es ist möglich, eine "anderthalb-Schleife" damit zu implementieren, obwohl dies möglicherweise nicht der beste Weg ist, dies zu tun:
quelle