Votre question

Utiliser GOTO en C

Tags :
  • Sequence
  • Programmation
Dernière réponse : dans Programmation
3 Avril 2009 15:45:34

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:
  1. void importationsequence (void)
  2. {
  3. int option, Nb_seq, x;
  4. char sequence;
  5. printf("Comment voulez vous entrer vos sequence?\n1- manuellement\n2 -en important depuis un fichier .txt\n\nTapez votre reponse:");
  6. scanf("%d", &option);
  7. if(option == 1){
  8. printf("Veuillez taper le nombre de sequences:\nNb_seq =\n");
  9. scanf("%d", &Nb_seq);
  10.  
  11. char text[]="seq.txt";
  12. FILE *fp1;
  13. fp1 =fopen(text, "w");x=1;
  14. do {
  15. printf("Veuillez taper la sequence:\n");
  16. scanf ("%s", &sequence);
  17. fprintf(fp1, ">seq_%d\n", x);
  18. fprintf(fp1, "%s\n", &sequence);
  19. x++;
  20. }
  21. while (x<=Nb_seq);
  22. fclose(fp1); }
  23.  
  24. else if (option==2) {}
  25. else { goto erreur;} ;
  26. }
  27. 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

3 Avril 2009 15:52:47

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:

  1. else if (option==2) {}
  2. else {
  3. printf("Vous avez entre un mauvais choix." );
  4. } ;
m
0
l
3 Avril 2009 17:21:57

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:

  1. else if (option==2) {}
  2. else {
  3. printf("Vous avez entre un mauvais choix." );
  4. } ;


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 ?
m
0
l
Contenus similaires
3 Avril 2009 21:34:34

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
m
0
l
a b L Programmation
3 Avril 2009 21:53:03

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:
  1. int importationsequence (void);


Après, si tu ne veux pas montrer le int pour ne pas confondre avec un entier, tu peux faire:
  1. typedef int tResult;
  2. tResult importationsequence (void);


La deuxième étape est de définir les erreurs constantes. Par exemple:
  1. enum {
  2. OK = 0x00,
  3. WARNING_ARE_YOU_SURE = 0x40,
  4. WARNING_DELETE,
  5. WARNING_NEW,
  6. WARNING_BIG,
  7. ERROR_INVALID_CHOICE = 0x80,
  8. ERROR_FILE_NOT_FOUND,
  9. ERROR_INVALID_SEQUENCE
  10. };


Dans le code, si tu veux retourner une erreur, tu fais un
  1. 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:
  1. #define MESSAGE_SIZE 256
  2.  
  3. tResult result;
  4. char message[MESSAGE_SIZE];
  5. //...
  6. result = importationsequence();
  7. if( result >= 0x80 )
  8. {
  9. printf("%s\n", GetResultMessage(result, message, MESSAGE_SIZE));
  10. // par exemple on arrête le programme
  11. return;
  12. }
  13. else if( result >= 0x40 )
  14. {
  15. printf("%s\n", GetResultMessage(result));
  16. // on affiche le message, mais on continue
  17. }

avec le GetResultMessage qui va bien:
  1. // For french users ;)
  2. #define MSG_ERROR_HEAD "Erreur : "
  3. #define MSG_WARNING_HEAD "Avertissement :
  4. #define MSG_OK_HEAD "Avertissement :
  5.  
  6. #define MSG_ERROR_INVALID_CHOICE "Vous avez entre un mauvais choix."
  7.  
  8. char * GetResultMessage(tResult result, char * message, int size)
  9. {
  10. char * remainingBuffer = message;
  11. int remainingSize = size;
  12. int headerSize = 0;
  13.  
  14. if (size < 1)
  15. return message;
  16. message[0] = '\0';
  17.  
  18. if(result >= 0x80)
  19. {
  20. // Set header
  21. headerSize = strlen(ERROR_HEAD) + 1;
  22.  
  23. if (headerSize > size)
  24. return message;
  25.  
  26. strcpy(message, ERROR_HEAD);
  27.  
  28. // Set message
  29. remainingBuffer = message + headerSize - 1;
  30. remainingSize = size - headerSize + 1;
  31.  
  32. switch(result)
  33. {
  34. case ERROR_INVALID_CHOICE:
  35.  
  36. msgSize = strlen(MSG_ERROR_INVALID_CHOICE) + 1;
  37.  
  38. if (msgSize > remainingSize)
  39. return message;
  40.  
  41. strcpy(message, MSG_ERROR_INVALID_CHOICE);
  42.  
  43. break;
  44. // etc
  45. default:
  46. // Afficher message inconnu
  47. }
  48. }
  49. // etc
  50.  
  51. return message;
  52. }

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. :) 
  1. typedef struct
  2. {
  3. int errorCode; // on garde le système de codes d'erreur
  4. int additionalDataSize;
  5. char additionnalData[256];
  6. } 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.
  1. additionalDataSize = 4;
  2. *((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 :)  ).

m
0
l
3 Avril 2009 21:54:54

Merci.

Finalement j'ai reussi a le faire marcher.
C'est impeccable.

Edit: j'avais pas vu le pave de CRicky.
Merci, vais lire ca en detail et voir ce que je suis capable d'appliquer :jap: 
m
0
l
Tom's guide dans le monde
  • Allemagne
  • Italie
  • Irlande
  • Royaume Uni
  • Etats Unis
Suivre Tom's Guide
Inscrivez-vous à la Newsletter
  • ajouter à twitter
  • ajouter à facebook
  • ajouter un flux RSS