web-dev-qa-db-fra.com

Déclaration de variable après goto Label

Aujourd'hui, j'ai trouvé une chose intéressante. Je ne savais pas que l'on ne pouvait pas déclarer une variable après une étiquette goto.

Compilation du code suivant

#include <stdio.h>
int main() {
    int x = 5;
    goto JUMP;
    printf("x is : %d\n",x);
JUMP:
    int a = 0;  <=== giving me all sorts of error..
    printf("%d",a);
}

donne des erreurs comme

temp.c: In function ‘main’:
temp.c:7: error: expected expression before ‘int’
temp.c:8: error: ‘a’ undeclared (first use in this function)
temp.c:8: error: (Each undeclared identifier is reported only once
temp.c:8: error: for each function it appears in.)

Maintenant, quelle est la logique derrière cela? J'ai entendu que on ne peut pas créer de variables à l'intérieur des instructions case de switch. Étant donné que JUMP se trouve dans la même portée (la portée de la fonction principale, dans mon cas) de l'instruction goto, je pense que la portée n'est pas un problème ici. Mais alors, pourquoi ai-je cette erreur?

66
Krishnabhadra

La syntaxe ne le permet tout simplement pas. §6.8.1 Déclarations étiquetées:

labeled-statement:
    identifier : statement
    case constant-expression : statement
    default : statement

Notez qu'aucune clause ne permet une "déclaration étiquetée". Cela ne fait tout simplement pas partie de la langue.

Vous pouvez bien sûr contourner cela, bien sûr, avec une déclaration vide.

JUMP:;
int a = 0;
84
Stephen Canon

Vous voulez un point-virgule après l'étiquette comme ceci:

 #include <stdio.h>
 int main() {
     int x = 5;
     goto JUMP;
     printf("x is : %d\n",x);
 JUMP: ;     /// semicolon for empty statement
     int a = 0; 
     printf("%d",a);
 }    

Ensuite, votre code compile correctement pour la norme C99, avec gcc -Wall -std=c99 -c krishna.c (J'utilise GCC 4.6 sur Debian/Sid/AMD64).

13

Une explication simple, autre que la spécification ne le dit pas, est que le compilateur s'attend à ce que le code après le goto soit quelque chose qui se compile en une opération dont il peut ensuite calculer le décalage, et donne un coup de pied parce que votre déclaration de variable n'est pas une instruction/bloc qu'il peut compiler dans un tel décalage.

6
jmoreno

Ma version gcc (4.4) donne cette erreur de compilation:

t.c:7: error: a label can only be part of a statement and a declaration is not a statement

. Ce message d'erreur dit tout.

6
Patrick B.

Si vous savez pourquoi vous ne pouvez pas créer de variables à l'intérieur de l'instruction case du commutateur, c'est essentiellement la même raison pour laquelle vous ne pouvez pas le faire aussi. Comme solution, vous pouvez essayer ceci,

#include <stdio.h>
int main() {
    int x = 5;
    goto JUMP;
    printf("x is : %d\n",x);
JUMP:
    {                                              //Note this
       int a = 0;  // <=== no more error..
       printf("%d",a);
    }                                             //Note this
}
2
COD3BOY

Eh bien, vous devez d'abord être cohérent. Il s'agit de LABEL ou label. Deuxièmement, l'étiquette fait partie de l'instruction et la déclaration ne répond pas suffisamment à la description.

Vous pouvez remplacer LABEL: avec label: ; puis il est plus facile de compiler.

EDIT: Maintenant que vous avez édité votre code partout, il devrait être JUMP: remplacé par JUMP: ; ;-)

Ce n'est pas à cause de l'étiquette en soi, c'est parce qu'il y a déjà des instructions (goto et printf). La dernière norme semble autoriser les déclarations de variables à des endroits arbitraires, mais tous les compilateurs ne sont pas entièrement conformes à la norme. De plus, les identificateurs sont sensibles à la casse en C et votre étiquette doit être la même aux deux endroits.

1
Alexey Frunze
#include <stdio.h>
int main() {
    int x = 5;
    goto JUMP;
    printf("x is : %d\n",x);
JUMP:
    printf("Do anything after label but dont declare 
    anything. even empty statement will also work 
    because label can only be part of a statement");
    int a = 0;  
    printf("%d",a);
}
0
Jeegar Patel