À travers une petite faute de frappe, j'ai accidentellement trouvé cette construction:
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;
}
Il semble que le printf
haut de la switch
déclaration soit valide, mais aussi complètement inaccessible.
J'ai obtenu une compilation propre, sans même un avertissement sur le code inaccessible, mais cela semble inutile.
Un compilateur doit-il signaler cela comme du code inaccessible?
Est-ce que cela sert à quelque chose que ce soit?
c
switch-statement
language-lawyer
abelenky
la source
la source
-Wswitch-unreachable
goto
entrer et sortir de la partie autrement inaccessible, qui peut être utile pour divers hacks.switch
c'est juste un conditionnelgoto
avec plusieurs étiquettes. Il y a plus ou moins les mêmes restrictions sur son corps que sur un bloc de code normal rempli d'étiquettes goto.Réponses:
Peut-être pas le plus utile, mais pas complètement inutile. Vous pouvez l'utiliser pour déclarer une variable locale disponible dans la
switch
portée.Le standard (
N1579 6.8.4.2/7
) a l'exemple suivant:PS BTW, l'exemple n'est pas du code C ++ valide. Dans ce cas (
N4140 6.7/3
, c'est moi qui souligne):Donc, le remplacer
int i = 4;
par enint i;
fait un C ++ valide.la source
i
est initialisé à 4, que me manque-t-il?static
, elle sera initialisée à zéro, il y a donc une utilisation sûre pour cela également.i = 4;
initialisation, donc elle n'a jamais lieu.case
, et je devais toujours utiliser des noms différents dans chacuncase
ou le définir en dehors du commutateur.Oui. Si au lieu d'une déclaration, vous mettez une déclaration avant la première étiquette, cela peut être parfaitement logique:
Les règles pour les déclarations et les instructions sont partagées pour les blocs en général, c'est donc la même règle qui autorise celle qui autorise également les instructions.
Il convient également de mentionner que si la première instruction est une construction de boucle, des étiquettes de casse peuvent apparaître dans le corps de la boucle:
Veuillez ne pas écrire de code comme celui-ci s'il existe un moyen plus lisible de l'écrire, mais il est parfaitement valide et l'
f()
appel est accessible.la source
{ /*code*/ switch(x) { } }
peut sembler plus propre mais c'est aussi faux .Il y a une utilisation célèbre de cet appareil appelé Duff's Device .
Ici, nous copions un tampon pointé par par
from
un tampon pointé parto
. Nous copions descount
instances de données.L'
do{}while()
instruction commence avant la premièrecase
étiquette et lescase
étiquettes sont incorporées dans ledo{}while()
.Cela réduit le nombre de branches conditionnelles à la fin de la
do{}while()
boucle rencontrées d'environ un facteur 4 (dans cet exemple; la constante peut être ajustée à la valeur souhaitée).Maintenant, les optimiseurs peuvent parfois le faire pour vous (surtout s'ils optimisent le streaming / les instructions vectorisées), mais sans optimisation guidée par le profil, ils ne peuvent pas savoir si vous vous attendez à ce que la boucle soit grande ou non.
En général, les déclarations de variables peuvent s'y produire et être utilisées dans tous les cas, mais être hors de portée une fois le commutateur terminé. (notez que toute initialisation sera ignorée)
De plus, un flux de contrôle qui n'est pas spécifique au commutateur peut vous amener dans cette section du bloc de commutateur, comme illustré ci-dessus, ou avec un
goto
.la source
do {
etcase 0:
peu importe, les deux servent à placer une cible de saut sur le premier*to = *from++;
.do {
est plus lisible. Oui, argumenter sur la lisibilité de l'appareil de Duff est stupide et inutile et probablement un moyen simple de devenir fou.En supposant que vous utilisez gcc sous Linux, cela vous aurait donné un avertissement si vous utilisez 4.4 ou une version antérieure.
L'option -Wunreachable-code a été supprimée dans gcc 4.4 .
la source
Non seulement pour la déclaration de variables, mais aussi pour le saut avancé. Vous pouvez bien l'utiliser si et seulement si vous n'êtes pas sujet au code de spaghetti.
Impressions
Il convient de noter que le commutateur-cas est l'une des clauses de flux de contrôle les plus rapides. Il doit donc être très flexible pour le programmeur, ce qui implique parfois des cas comme celui-ci.
la source
nocase:
etdefault:
?i=4
ne se déclenche pasnocase
.Il convient de noter qu'il n'y a pratiquement aucune restriction structurelle sur le code dans l'
switch
énoncé ou sur l'emplacement descase *:
étiquettes dans ce code *. Cela rend possible des astuces de programmation comme le périphérique de duff , dont une implémentation possible ressemble à ceci:Vous voyez, le code entre le
switch(n%8) {
et lecase 7:
étiquette est définitivement accessible ...* Comme Supercat l'a heureusement souligné dans un commentaire : depuis C99, ni un
goto
ni une étiquette (que ce soit unecase *:
étiquette ou non) ne peut apparaître dans le cadre d'une déclaration contenant une déclaration VLA. Il n'est donc pas correct de dire qu'il n'y a pas de restrictions structurelles sur le placement descase *:
étiquettes. Cependant, l'appareil de duff est antérieur à la norme C99, et il ne dépend pas de toute façon de VLA. Néanmoins, je me suis senti obligé d'insérer un "virtuellement" dans ma première phrase à cause de cela.la source
goto
ni neswitch/case/default
peuvent apparaître dans la portée d'un objet ou d'un type à déclaration variable. Cela signifie effectivement que si un bloc contient des déclarations d'objets ou de types de tableaux de longueur variable, toutes les étiquettes doivent précéder ces déclarations. Il y a un peu de verbiage déroutant dans la norme qui suggère que dans certains cas, la portée d'une déclaration VLA s'étend à l'intégralité d'une instruction switch; voir stackoverflow.com/questions/41752072/… pour ma question à ce sujet.Vous avez obtenu votre réponse concernant l' option requise
gcc
-Wswitch-unreachable
pour générer l'avertissement, cette réponse consiste à élaborer sur la partie convivialité / valeur .Citant directement
C11
, chapitre §6.8.4.2, (c'est moi qui souligne )Ce qui est très explicite. Vous pouvez l'utiliser pour définir une variable de portée locale qui n'est disponible que dans la
switch
portée de l' instruction.la source
Il est possible d'implémenter une "boucle et demie" avec, bien que ce ne soit pas la meilleure façon de le faire:
la source