2 votes

Comment une étiquette est-elle autorisée entre "else-if" ?

Voici un exemple simple (non lié à une plateforme spécifique) :

#include <stdio.h>
int main()
{
    for(int i = 0; i < 3; ++i)
        if(i == 0) printf("1\n");
        else if (i == 1) goto checkfor2;
        else checkfor2: if(i == 2 || i == 1) printf("2\n");
}

En direct sur wandbox.

Mon code original Windows à partir duquel cette question a été soulevée :

#include <Windows.h>
#include <stdbool.h>
main() //exemple avec API Win32
{
    for (;;) //boucle infinie pour ma logique principale
        if (WaitForSingleObject(hEvent, 1) != WAIT_TIMEOUT, true) //#1 vérifier un événement
            //oops définir comma true pour tester ce code d'événement
        {
            //faire quelque chose
            //mais ici ça va boucler indéfiniment et ne vérifiera pas #3
            //donc si quelque chose ne va pas, je ne peux pas sortir

            //alors moi, malin, j'ai fait ce qui suit :

            goto checkforexit; //voir l'étiquette sur #3 ci-dessous
        }
        else if (WaitForSingleObject(hEvent2, 1) != WAIT_TIMEOUT) //#2 vérifier un autre événement
        {
            //faire quelque chose d'autre
        }
        else checkforexit: /*wow entre else et if*/ if (GetAsyncKeyState(VK_BACK) & 0x8000 && GetAsyncKeyState(VK_CONTROL) & 0x8000) //#3 vérifier le raccourci clavier pour la sortie
            exit(0); //code de terminaison
}

J'étais surpris que cela fonctionne - il semble que à la fois le else if d'origine et l'étiquette du if fonctionnent comme prévu - comment est-ce possible ?

Je vous serais reconnaissant si vous ajoutez une citation du standard C.

Cela fonctionne à la fois sur gcc (comme testé sur le wandbox) et MSVC.

6voto

Eric Postpischil Points 36641

Le libellé fait en fait partie de l'instruction if; l'instruction if est libellée.

La norme C 2018 6.8 définit une instruction (un jeton dans la grammaire formelle du langage C) comme l'un des éléments suivants :

  • instruction-étiquetée
  • instruction-composée
  • instruction-d'expression
  • instruction-de-sélection
  • instruction-d'itération
  • instruction-de-saut

Une instruction if … else est définie en 6.8.4 comme l'une des options pour une instruction-de-sélection :

  • if ( expression ) instruction else instruction

Comme vous pouvez le voir, ce qui suit le else est une instruction, et une instruction peut être une instruction-étiquetée, dont une forme est "identifiant : instruction". (Les autres formes utilisent les libellés case et default pour une instruction switch.)

Ce n'est pas un obstacle pour le compilateur car il inclut simplement le transfert de contrôle d'une instruction goto vers l'étiquette dans son graphe de flux de contrôle, qui inclut déjà des sauts tels que du if vers le else (car la première instruction est sautée si l' expression est fausse), de la fin d'une boucle while vers le début, d'une instruction break vers l'extérieur d'une boucle for, et même de déclarations goto vers des étiquettes à l'intérieur de boucles while ou for. En construisant un graphe de flux de contrôle général, le compilateur est capable de gérer un flux de contrôle arbitraire et ne se soucie pas de la "programmation structurée". La programmation structurée est un outil pour aider les humains, mais les logiciels peuvent gérer des cas arbitraires sans cet outil.

Vous pouvez largement utiliser des étiquettes pour sauter arbitrairement à l'intérieur d'une fonction, mais un problème survient lorsque vous sautez dans une portée dans laquelle un tableau de longueur variable ou un autre type modifié de manière variable est déclaré. La norme C ne définit pas le comportement si vous le faites, comme par exemple :

if (drapeau)
    goto étiquette;
while (foo)
{
    int bar[n];
    étiquette: // Erreur, la déclaration de `bar` est sautée.
    …
}

3voto

Lundin Points 21616

La syntaxe formelle d'une étiquette peut être trouvée à C11 6.8.1 :

déclaration-étiquetée :
identificateur : instruction

instruction peut être l'un des suivants :

instruction :
déclaration-étiquetée
instruction-composée
instruction-expression
instruction-sélection
instruction-itération
instruction-saut

if est une instruction de sélection, donc le code comme my_label : if(something) ; est tout à fait correct du point de vue de la syntaxe.

Quant à "else if", il ne constitue en réalité pas un élément de syntaxe d'instruction distinct (il s'agit d'un malentendu courant) - c'est simplement un else contenant un if imbriqué écrit sur la même ligne. Mais nous aimons les écrire ensemble pour améliorer la lisibilité visuelle. Pour clarifier l'indentation, votre code aurait pu être écrit de cette manière :

#include 
int main()
{
    for(int i = 0; i < 3; ++i)
        if(i == 0) 
            printf("1\n");
        else 
            if (i == 1) 
                goto checkfor2;
        else 
            checkfor2: if(i == 2 || i == 1) 
                printf("2\n");
}

checkfor2: if est valide, conformément à la syntaxe précédemment citée.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X