Utiliser GOTO en C
Dernière réponse : dans Programmation
Bonjour
Alors oui je sais, son utilisation est tres deconseillee mais c'est ce qui est le plus propre dans le cas auquel je suis soumis et j'aimerais bien comprendre comment l'utiliser.
Alors j'ai une partie de mon code:
Donc j'ai juste un souci avant le lancement:
error: expected identifier before '}' token =>else { goto erreur;} ;
error: expected unqualified-id before ':' token =>else { goto erreur} ; =>erreur : printf("Vous avez entre un mauvais choix.");
Ai je mal itilise mon goto ?
Merci
Alors oui je sais, son utilisation est tres deconseillee mais c'est ce qui est le plus propre dans le cas auquel je suis soumis et j'aimerais bien comprendre comment l'utiliser.
Alors j'ai une partie de mon code:
void importationsequence (void)
{
int option, Nb_seq, x;
char sequence;
printf("Comment voulez vous entrer vos sequence?\n1- manuellement\n2 -en important depuis un fichier .txt\n\nTapez votre reponse:");
scanf("%d", &option);
if(option == 1){
printf("Veuillez taper le nombre de sequences:\nNb_seq =\n");
scanf("%d", &Nb_seq);
char text[]="seq.txt";
FILE *fp1;
fp1 =fopen(text, "w");x=1;
do {
printf("Veuillez taper la sequence:\n");
scanf ("%s", &sequence);
fprintf(fp1, ">seq_%d\n", x);
fprintf(fp1, "%s\n", &sequence);
x++;
}
while (x<=Nb_seq);
fclose(fp1); }
else if (option==2) {}
else { goto erreur;} ;
}
erreur : printf("Vous avez entre un mauvais choix.");
Donc j'ai juste un souci avant le lancement:
error: expected identifier before '}' token =>else { goto erreur;} ;
error: expected unqualified-id before ':' token =>else { goto erreur} ; =>erreur : printf("Vous avez entre un mauvais choix.");
Ai je mal itilise mon goto ?
Merci
Autres pages sur : utiliser goto
Lassé par la pub ? Créez un compte
Tybbow a dit :
Normalement, tu ouvres { et tu fermes }Ton label "erreur" est dans une partie du programme qu'il ne comprend pas!
Sinon, pourquoi ne pas simplement créer un p'tit truc du genre:
else if (option==2) {} else { printf("Vous avez entre un mauvais choix." ); } ;
Parce que je veux reutiliser le meme message plusieurs fois donc "goto erreur" c'est plus propre qu'une enieme boucle.
Dans mon programme j'ai une partie avec 16 boucles imbriquees, si j'arrive a comprendre comment utiliser goto je pourrais condenser.
Ce programme marchait avec un if/else if mais je cherche a le rendre plus compact et lisible.
Et que je mette ou non des {} autour de:
- goto erreur;
- erreur : printf( .....);
Ca me donne le meme message.
Comment doit on declarer un GOTO ?
N'utilise pas goto. Non, sérieusement. N'utilise pas goto, à moins de faire de la programmation système (c'est le seul endroit où je l'ai vu bien utilisé), et encore. C'est se faire chier pour rien (la preuve); une mauvaise habitude (pour un goto propre, j'en ai vu des dizaines sales), et ça n'est pas plus lisible qu'une énième boucle (après tout, ton goto pourrait partir un peu n'importe où dans le code, sans la ). On peut toujours faire sans. Réfléchis à la logique de ce que tu veux faire (quitter? suffit de faire un return; afficher un message? ça peut se faire dans la boucle, etc.) et réorganise ton code en conséquence.
Le problème ici, c'est que ton étiquette erreur: se trouve en dehors du "scope" de la fonction (délimité par les void importationsequence (void){} ).
Donc, elle est inaccessible.
EDIT: tu as des exemples ici:
http://aelinik.free.fr/c/ch14.htm
Le problème ici, c'est que ton étiquette erreur: se trouve en dehors du "scope" de la fonction (délimité par les void importationsequence (void){} ).
Donc, elle est inaccessible.
EDIT: tu as des exemples ici:
http://aelinik.free.fr/c/ch14.htm
Ta syntaxe est presque correct: ton label "erreur:" doit se trouver à l'intérieur de la fonction. Toi, tu l'as mis à l'extérieur. Le compilateur cherche alors une définition de variable ou de fonction, alors le :, il ne connait pas.
Mais programmer en C comme en VB, c'est caca.
Un goto n'est pas propre. Seulement en assembleur, c'est propre (et en Basic parce que les If ne sont pas beaux).
Un truc propre (et pro) en C, c'est de retourner l'erreur en sortie de fonction:
Après, si tu ne veux pas montrer le int pour ne pas confondre avec un entier, tu peux faire:
La deuxième étape est de définir les erreurs constantes. Par exemple:
Dans le code, si tu veux retourner une erreur, tu fais un
Evidemment, on ne traite pas l'erreur dans la fonction de traitement, parce que si tu veux mettre à jour une ou plusieurs erreur, tu es sûr de passer à côté de quelque chose. On peut par exemple implémenter comme ceci:
avec le GetResultMessage qui va bien:
En C++, c'est plus facile, on utilise string (ou similaire) et on ne s'embête plus sur les tailles (géré par l'objet).
Bon, j'ai mis les warning, mais on peu simplifier par 1 OK et une suite d'erreurs.
Ensuite, on peut compléter tout ça en utilisant une structure au lieu d'un int, ça prend plus de place sur la pile, mais maintenant l'espace n'est plus un problème.
Par exemple, si lors d'un mauvais choix on veut indiquer ce qu'était le mauvais choix, on peut le stocker dans les donnée additionnelles.
Du coup, il faut en tenir compte dans le GetResultMessage().
Là encore, en C++ c'est plus simple, car il suffit de définir une classe qui continent les méthodes getResultMessage(), le code d'erreur et autres données). En C++, on a aussi la possibilité de traiter les erreurs par exceptions (c'est un choix à faire).
Bon, évidemment, je pousse au maximum la gestion des erreurs. Il est peut-être plus simple de retourner un int (en utilisant quand même des define ou enum pour être propre) et de traiter au cas par cas.
Ceci dit, je complique tout parce que:
1. ça limite l'apparition de bugs dans le traitement d'erreur
2. une fois la structure mise en place, ajouter une erreur est un jeu d'enfant
3. faciliter l'ajout d'erreur pousse à traiter un maximum de cas d'erreur afin de présenter un logiciel ergonomique à l'utilisation. Un logiciel dont les erreurs sont mal gérées se voient rapidement (comportements bizarres + crashes fréquents)
4. ça aide pour l'internationalisation, car les messages centralisés sont facilement manipulables.
5. ça aide à la correction du traitement de l'erreur (et pas seulement changer le texte)
6. un bon traitement d'erreur permet de bien debugger le programme car ça permet de faire remonter les origines d'un bug.
Sinon, que ce soit pour une gestion d'erreur ou pas, si je regarde un programme professionnel dont le source contient des goto, j'arrête de le lire et je jette le code source (et le programme qui va avec
).
Mais programmer en C comme en VB, c'est caca.
Un goto n'est pas propre. Seulement en assembleur, c'est propre (et en Basic parce que les If ne sont pas beaux).
Un truc propre (et pro) en C, c'est de retourner l'erreur en sortie de fonction:
int importationsequence (void);
Après, si tu ne veux pas montrer le int pour ne pas confondre avec un entier, tu peux faire:
typedef int tResult; tResult importationsequence (void);
La deuxième étape est de définir les erreurs constantes. Par exemple:
enum { OK = 0x00, WARNING_ARE_YOU_SURE = 0x40, WARNING_DELETE, WARNING_NEW, WARNING_BIG, ERROR_INVALID_CHOICE = 0x80, ERROR_FILE_NOT_FOUND, ERROR_INVALID_SEQUENCE };
Dans le code, si tu veux retourner une erreur, tu fais un
return ERROR_INVALID_CHOICE;
Evidemment, on ne traite pas l'erreur dans la fonction de traitement, parce que si tu veux mettre à jour une ou plusieurs erreur, tu es sûr de passer à côté de quelque chose. On peut par exemple implémenter comme ceci:
#define MESSAGE_SIZE 256 tResult result; char message[MESSAGE_SIZE]; //... result = importationsequence(); if( result >= 0x80 ) { printf("%s\n", GetResultMessage(result, message, MESSAGE_SIZE)); // par exemple on arrête le programme return; } else if( result >= 0x40 ) { printf("%s\n", GetResultMessage(result)); // on affiche le message, mais on continue }
avec le GetResultMessage qui va bien:
// For french users ;) #define MSG_ERROR_HEAD "Erreur : " #define MSG_WARNING_HEAD "Avertissement : #define MSG_OK_HEAD "Avertissement : #define MSG_ERROR_INVALID_CHOICE "Vous avez entre un mauvais choix." char * GetResultMessage(tResult result, char * message, int size) { char * remainingBuffer = message; int remainingSize = size; int headerSize = 0; if (size < 1) return message; message[0] = '\0'; if(result >= 0x80) { // Set header headerSize = strlen(ERROR_HEAD) + 1; if (headerSize > size) return message; strcpy(message, ERROR_HEAD); // Set message remainingBuffer = message + headerSize - 1; remainingSize = size - headerSize + 1; switch(result) { case ERROR_INVALID_CHOICE: msgSize = strlen(MSG_ERROR_INVALID_CHOICE) + 1; if (msgSize > remainingSize) return message; strcpy(message, MSG_ERROR_INVALID_CHOICE); break; // etc default: // Afficher message inconnu } } // etc return message; }
En C++, c'est plus facile, on utilise string (ou similaire) et on ne s'embête plus sur les tailles (géré par l'objet).
Bon, j'ai mis les warning, mais on peu simplifier par 1 OK et une suite d'erreurs.
Ensuite, on peut compléter tout ça en utilisant une structure au lieu d'un int, ça prend plus de place sur la pile, mais maintenant l'espace n'est plus un problème.
typedef struct { int errorCode; // on garde le système de codes d'erreur int additionalDataSize; char additionnalData[256]; } tResult;
Par exemple, si lors d'un mauvais choix on veut indiquer ce qu'était le mauvais choix, on peut le stocker dans les donnée additionnelles.
additionalDataSize = 4; *((int *)additionnalData) = option;
Du coup, il faut en tenir compte dans le GetResultMessage().
Là encore, en C++ c'est plus simple, car il suffit de définir une classe qui continent les méthodes getResultMessage(), le code d'erreur et autres données). En C++, on a aussi la possibilité de traiter les erreurs par exceptions (c'est un choix à faire).
Bon, évidemment, je pousse au maximum la gestion des erreurs. Il est peut-être plus simple de retourner un int (en utilisant quand même des define ou enum pour être propre) et de traiter au cas par cas.
Ceci dit, je complique tout parce que:
1. ça limite l'apparition de bugs dans le traitement d'erreur
2. une fois la structure mise en place, ajouter une erreur est un jeu d'enfant
3. faciliter l'ajout d'erreur pousse à traiter un maximum de cas d'erreur afin de présenter un logiciel ergonomique à l'utilisation. Un logiciel dont les erreurs sont mal gérées se voient rapidement (comportements bizarres + crashes fréquents)
4. ça aide pour l'internationalisation, car les messages centralisés sont facilement manipulables.
5. ça aide à la correction du traitement de l'erreur (et pas seulement changer le texte)
6. un bon traitement d'erreur permet de bien debugger le programme car ça permet de faire remonter les origines d'un bug.
Sinon, que ce soit pour une gestion d'erreur ou pas, si je regarde un programme professionnel dont le source contient des goto, j'arrête de le lire et je jette le code source (et le programme qui va avec
).Lassé par la pub ? Créez un compte