Partage
  • Partager sur Facebook
  • Partager sur Twitter

[Bêta ON] Éviter les erreurs en langage C

Dans la catégorie "C" par GuilOooo

    23 octobre 2011 à 17:11:13

    Lire le tutoriel
    Tuto ouvert aux bêta-tests
    Réservé aux membres

    • Partager sur Facebook
    • Partager sur Twitter
      23 octobre 2011 à 17:11:14

      Salut tout le monde ! :)

      Ce tutoriel est un concentré de bonnes pratiques à garder à l'esprit lorsqu'on programme en langage C. J'y explique que faire pour être dans les meilleures conditions possibles lorsqu'une erreur survient, et comment réagir face à un bug.

      Le tutoriel est rédigé suivant un plan du plus particulier au plus général. On se concentre principalement sur la bibliothèque standard du C et sur la SDL, pour rester dans l'esprit du tuto de M@teo21.

      Je vous souhaite une bonne lecture et vous remercie d'avance pour vos commentaires !
      GuilOooo
      • Partager sur Facebook
      • Partager sur Twitter
      J'ai déménagé sur Zeste de savoir — Ex-manager des modérateurs.
        23 octobre 2011 à 20:38:51

        Pas mal du tout, complet, synthétique… Ça devrait (on espère) alléger les habitués du forum de pas mal de questions de débutants.

        Petite relecture :

        Citation : tuto

        Pour l'expliquer, il faut


        Citation : tuto

        héxadécimal hexadécimal


        Citation : tuto

        Lorsque nous passons cette adresse à la fonction fgets, cette dernière tentera innocemment de lire la case pointée par NULL... Et déclanchera déclenchera un plantage du programme !




        Ah oui, là-dedans :

        Citation : tuto

        void vider_buffer(void)
        {
            int c;
            do
            {
                c = fgetc(stdin);
            } while(c > 0 && c != '\n');
        }
        
        Ce ne serait pas mieux de remplacer c>0 par c!=EOF (pour la lisibilité) ?


        Citation : tuto

        Ainsi, des lignes telles que :

        i = i++;
        

        ont un comportement indéterminé. La valeur de i est en effet incrémentée une première fois par l'opérateur ++, puis changée par l'affectation =.

        Pour être plus précis, i++ renverra l'ancienne valeur de i à l'opérateur =, tandis que i sera incrémenté on ne sait pas quand… On ne sait pas si ce sera avant l'assignation (auquel cas la valeur finale de i sera inchangée) ou après (i sera finalement incrémenté), car il n'y a pas de point de séquence à l'opérateur d'assignement.


        Citation : tuto

        Certains zéros croient que le débogueur correspond à ce que M@teo21 nomme « la zone de la mort »


        Citation : tuto

        Je vais vous révéler un scoop : le compilateur est votre meilleur ami.

        Soit on révèle un secret, soit on fait un scoop. Pas les deux. :p

        Citation : tuto

        Si une segfault survient, il peut vous indiquer la fonction, et même la ligne où le problème est survenu, ce qui peut être d'une grande aide.


        Citation : tuto

        Les marcos macros dont le nom commence par un « E » sont réservées pour les codes d'erreur.

        La variable errno ainsi que les codes d'erreurs sont déclarées dans l'en-tête errno.h, qui est lui-même inclus dans de nombreux en-têtes standards (notamment stdio.h).


        Citation : tuto

        Je ne parle pas ici de « déboguer à coups de printf », c'est-à-dire de rajouter des printfs juste avant un crash du programme pour essayer de comprendre ce qui se passe. Nous parlerons du débogage plus loin dans ce tutoriel. :)
        Ah non, tu parles (brièvement) du déboggage avant ceci.

        Citation : tuto

        Le plus souvent, on peut dénicher les documentations en quelques minutes via un moteur de recherche tel que Google.


        Citation : tuto

        Pour vous aider, voici une liste non-exhaustive de fonctions dont il faut tester la valeur de retour.



        Citation : tuto

        en dernier ressort, venez vous nous voir sur le forum ! :)



        Prévois-tu un QCM ?
        • Partager sur Facebook
        • Partager sur Twitter
        Anonyme
          23 octobre 2011 à 21:16:35

          Bonjour, :)

          Je trouve ces tutoriel bien rédiger, facile a comprendre, éviterais de nombreuses questions sur le forum, seulement, n'as tu pas peur que cela soit considérer comme un TEA ?

          Je te donne mon avis: Pour moi c'est un TEA, car il explique les erreurs "courante" que l'on peut faire...

          Quoi qu'il en soit, bonne chance a toi :) .

          Cordialement Eloyas
          • Partager sur Facebook
          • Partager sur Twitter
            23 octobre 2011 à 21:26:03

            Citation : Eloyas

            n'as tu pas peur que cela soit considérer comme un TEA ?



            Franchement, je me pose la question.

            C'est peut-être un TEA dans le sens où je parle de très nombreux points en les énumérants. Mais je donne aussi beaucoup de principes et d'idées très générales. Je ne me contente pas de dire « suivez ces étapes l'une après l'autre pour éviter des erreurs », je donne surtout des conseils, des habitudes. Ça donne une forme un peu particulière au résultat, j'en conviens.

            Dites-moi ce que vous en pensez.

            Pour Maëlan, merci beaucoup ! J'intègre toutes ces corrections demain. :)

            Edit : j'ai fait la plupart des corrections maintenant, finalement. Merci encore !
            • Partager sur Facebook
            • Partager sur Twitter
            J'ai déménagé sur Zeste de savoir — Ex-manager des modérateurs.
              24 octobre 2011 à 10:58:26

              Tiens donc, enfin un tutoriel sur C, ça commençait à manquer ces temps-ci.
              Ce Bêta tombe à pic, car j'étais justement en train de discuter des comportements indéterminés/non spécifiés par MP avec un autre membre.
              A coup sûr, ce cours serait un bon moyen d'échappement sur le forum C ; on revient souvent aux mêmes questions.

              L'utilisation du compilateur (flags avancés) et surtout du débogueur sont étrangement peu courant sur ce site, et pourtant, depuis que j'utilise valgrind, ma vie a changé. :-° (en parlant de valgrind, un petit lien dans la partie débogueur vers ce tutoriel ne serait pas de trop).

              Bon, je ne pense pas qu'il faille s'étaler sur les comportements indéterminés ; ça peut aller très loin (pour les intéressés, ces trois articles : 1/3, 2/3 et 3/3 sont très sympathiques).

              Dans la partie « Règler son compilateur », je trouve ce passage un peu trop subjectif :

              Citation

              Les options de GCC permettant d'avoir plus de messages d'avertissement (warnings) sur votre code sont les suivantes :

              -Wall -Wextra -Wunreachable-code -Wwrite-strings -Wstrict-prototypes


              Ça peut aller très loin, et les avis divergent. Personnellement, j'utilise :

              -W -Wall -Wextra -pedantic


              Mais je n'en y connais pas grand chose.
              -ed- conseillait même ça :

              -ansi -O2 -Wchar-subscripts -Wcomment -Wformat=2 -Wimplicit-int
              -Werror-implicit-function-declaration -Wmain -Wparentheses
              -Wsequence-point -Wreturn-type -Wswitch -Wtrigraphs -Wunused
              -Wuninitialized -Wunknown-pragmas -Wfloat-equal -Wundef
              -Wshadow -Wpointer-arith -Wbad-function-cast -Wwrite-strings
              -Wconversion -Wsign-compare -Waggregate-return -Wstrict-prototypes
              -Wmissing-prototypes -Wmissing-declarations -Wmissing-noreturn
              -Wformat -Wmissing-format-attribute -Wno-deprecated-declarations
              -Wpacked -Wredundant-decls -Wnested-externs -Winline -Wlong-long
              -Wunreachable-code


              Mais bon, c'est un peu terrifiant, d'autant plus que certains flags laissent à désirer.
              En fait, ce qui m'a gêné, c'est le ton affirmatif de la phrase introductive...

              Pour l'histoire du TEA, aux dernières nouvelles developpez.com n'en est pas fanatique, et pourtant :

              Les pièges du C
              Les erreurs courantes en C

              Bon, le deuxième lien n'a pas vraiment de rapport avec le présent tutoriel, mais le premier m'a paru très intéressant, pourquoi ne pas aller chercher un peu plus dans la profondeur ? :)

              Quitte à faire un tutoriel sur la gestion des erreurs, pourquoi ne pas consacrer carrément une mini-partie à l'utilisation de <errno.h> (en comptant strerror de string.h et perror de stdio, les traîtres ^^ ).
              Par exemple, j'utilise cette macro bien sale bien dégueulasse dans quasiment tous mes projets.

              #define PRINT_ERROR(s)                                                        \
                  do {                                                                      \
                      (void) fprintf(stderr, "----------------------------------------"     \
                                             "----------------------------------------\n"   \
                                             "\t\t\t\t\tERROR\n\n"                          \
                                             "Fonction    : %s\n"                           \
                                             "File        : %s\n"                           \
                                             "Line        : %d\n"                           \
                                             "Description : %s\n"                           \
                                             "----------------------------------------"     \
                                             "----------------------------------------\n",  \
                                             s, __FILE__, __LINE__, strerror(errno));       \
                  } while (0)
              


              Je trouve également étrange de traiter la SDL au même niveau que la lib standard, mais c'est vrai qu'elle est très utilisée sur le sdz.

              Il serait peut-être également bien d'insister sur la doc, quitte à mettre un lien vers un des sites proposant une doc sur C. Vraiment indispensable pour tester les valeurs de retour...

              Bon, en tout cas, belle initiative.
              • Partager sur Facebook
              • Partager sur Twitter
              Staff désormais retraité.
                24 octobre 2011 à 11:50:08

                Citation : lucas

                #define PRINT_ERROR(s)                                                        \
                    do {                                                                      \
                        (void) fprintf(stderr, "----------------------------------------"     \
                                               "----------------------------------------\n"   \
                                               "\t\t\t\t\tERROR\n\n"                          \
                                               "Fonction    : %s\n"                           \
                                               "File        : %s\n"                           \
                                               "Line        : %d\n"                           \
                                               "Description : %s\n"                           \
                                               "----------------------------------------"     \
                                               "----------------------------------------\n",  \
                                               s, __FILE__, __LINE__, strerror(errno));       \
                    } while (0)
                

                <3
                Mais quel est l’intérêt du do{}while; ?

                Pour valgrind, je te plussois lucas-84 (même si ce débogueur à certains défauts). ;)


                Pour les infos sur les erreurs des fonctions TTF, je crois que c'est : TTF_GetError(); ;) Même si SDL_GetError() pourrait fonctionner, je n'ai jamais essayé.
                Je pense que tu devrais un titi peu plus appuyer sur le fait de toujours vérifier les retours de fonctions (j'écris ça sans trop penser à ma bio hein :-°) car j'estime que pas mal de problèmes de prog' présenté sur le forum C sont causés par le manque (total) de vérifs'.

                Sinon, je trouve ce tuto très bien, clair etc... :D
                • Partager sur Facebook
                • Partager sur Twitter
                  24 octobre 2011 à 15:30:25

                  Je m'étais fait la même réflexion que lucas-84 concernant les options de warnings, mais vu que plus loin tu donnes le lien vers une liste plus complète, ça passe. Enfin, c'est vrai que la phrase introductive est un peu trop catégorique. Je ne me rappelle plus de la phrase exacte, mais en gros elle dit « C'est ça qu'il faut mettre ». OK pour -Wall -Wextra car tout le monde semble à peu près d'accord pour les utiliser, mais pour le reste c'est plus personnel.
                  • Partager sur Facebook
                  • Partager sur Twitter
                    24 octobre 2011 à 20:09:09

                    Merci pour vos commentaires !

                    Je prends en compte vos remarques concernant la phrase d'introduction des warnings, je vais la modifier.

                    Bonne idée valgrind, je vais rajouter le lien.

                    Je vais également rajouter une petite bibliographie comprenant les liens que lucas-84 a mentionné.

                    Liens vers la doc : j'ai déjà mis trois liens vers la doc de la lib standard, je vois pas ce que je peux faire de plus. :p

                    La SDL au même niveau que la libstd : je vois vraiment ce tuto comme un couteau suisse à l'usage du débutant sur le forum C. Je suis donc dans le prolongement du tuto de M@teo21, qui parle de la lib standard et de la SDL.

                    TTF_GetError : je vérifie dans la doc et je l'ajoute.

                    En tous cas, merci encore pour vos remarques !

                    EDIT : ai pris en compte le gros de vos suggestions.

                    • Partager sur Facebook
                    • Partager sur Twitter
                    J'ai déménagé sur Zeste de savoir — Ex-manager des modérateurs.
                      25 octobre 2011 à 16:14:02

                      Autre point qui aurait mérité d'être traité (car je pense que c'est en thème) : la différence entre les problèmes contextuels (plus de mémoire, fichier corrompu ou inexistant, socket fermée, etc) (qui requièrent des tests) et les erreurs d'algo (/d'utilisation des algos).

                      Souvent on écrit nos algos en faisant des suppositions (comme les théorèmes en maths), et on sait souvent qu'en dehors du domaine de validité des arguments (par exemple), il ne faut rien attendre de telle ou telle fonction. Dans ces cas là, on peut mettre en place des assertions qui s'occupent de vérifier les préconditions (postconditions et invariants aussi) des fonctions -- plutôt que de laisser des comportements toujours non définis dans nos codes, ou de faire de la programmation défensive qui laisse le programme tourner malgré les erreurs de codage.

                      Autre sujet connexe : les tests unitaires.
                      • Partager sur Facebook
                      • Partager sur Twitter
                      C++: Blog|FAQ C++ dvpz|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS| Bons livres sur le C++| PS: Je ne réponds pas aux questions techniques par MP.
                      Anonyme
                        25 octobre 2011 à 16:55:24

                        Salut,

                        Je viens de lire le tuto il est pas mal du tout. :)

                        Par contre, je pense que tu pourrais rajouter la détection d'un code C compilé avec un compilateur C++ :

                        #ifdef __cplusplus
                        #error Vous utilisez un compilateur C++ pour compiler un code C.
                        #endif
                        


                        Parce que des fois le fait de compiler en C++ peut amener des erreurs (au niveau des includes ou bien d'une conversion).

                        Et puis si tu veux celle du C89/C99 :

                        #ifdef __STDC_VERSION__
                        #if __STDC_VERSION__ >= 199901L
                        #error Vous utilisez la norme C99 sur un projet C_ansi.
                        #endif
                        
                        </span>

                        Voilà
                        • Partager sur Facebook
                        • Partager sur Twitter
                          25 octobre 2011 à 17:14:14

                          Citation : lmghs

                          Autre point qui aurait mérité d'être traité (car je pense que c'est en thème) : la différence entre les problèmes contextuels (plus de mémoire, fichier corrompu ou inexistant, socket fermée, etc) (qui requièrent des tests) et les erreurs d'algo (/d'utilisation des algos). [...]



                          C'est intéressant. Comment le vois-tu, concrètement ? Faire une sous-partie sur assert, la programmation défensive, les préconditions/postconditions, etc ?

                          Pour informaticienzero : je rajoute ça à l'endroit où je parle du cast de void* en d'autres pointeurs (malloc). Par contre, je ne pense pas ajouter la macro qui détecte la version du compilateur ; ça paraît un peu trop pointu pour les zéros du forum de C (ça entraînera plus de confusions qu'autre chose).
                          • Partager sur Facebook
                          • Partager sur Twitter
                          J'ai déménagé sur Zeste de savoir — Ex-manager des modérateurs.
                            26 octobre 2011 à 18:52:03

                            D'une certaines façon, c'est une rubrique à part.
                            Il y a une partie théorique qui aborde
                            - programmation par contrat
                            - programmation défensive
                            - gestion des cas non nominaux, mais probables
                            - TU
                            - ...

                            Et une partie pratique qui va indiquer quoi utiliser et quand. Et comment. Typiquement, la PpC à la sauce assert (i.e. orientée erreurs de programmation) se marie à merveille avec le débuggueur.
                            Presque cela mériterait un tuto à part entière.

                            Pour le comment des TU ... le problème c'est que pour le C et le C++ il existe beaucoup trop de frameworks de TU. Certains sont d'une ancienne génération et moins bien ficelés (CppUnit), d'autres sont pratiquement équivalents (boost, Cxxtest, google, CTests, Fructose, etc). Et de plus souvent ils visent plus le C++ que le C (quoiqu'il me semble avoir vu un truc pour le C une fois).
                            Cela mériterait aussi un tuto à part entière (par framework quasiment, même si les principes reviennent)
                            • Partager sur Facebook
                            • Partager sur Twitter
                            C++: Blog|FAQ C++ dvpz|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS| Bons livres sur le C++| PS: Je ne réponds pas aux questions techniques par MP.
                              27 octobre 2011 à 20:16:39

                              On peut alors songer à les mentionner, de façon à ce que les gens intéressés se manifestent et qu'une demande se crée ?

                              Je dois avouer que je n'ai pas les compétences pour rédiger des tutos entiers sur ces points, bien qu'ils soient très intéressants.
                              • Partager sur Facebook
                              • Partager sur Twitter
                              J'ai déménagé sur Zeste de savoir — Ex-manager des modérateurs.
                                30 octobre 2011 à 23:10:01

                                Tout ce qu'il faut savoir pour les fichiers ouverts en lecture/écriture :

                                Citation

                                When a file is opened with update mode ('+' as the second or third character in the above list of mode argument values), both input and output may be performed on the associated stream. However, output shall not be directly followed by input without an intervening call to the fflush function or to a file positioning function (fseek, fsetpos, or rewind), and input shall not be directly followed by output without an intervening call to a file positioning function, unless the input operation encounters end- of-file. Opening (or creating) a text file with update mode may instead open (or create) a binary stream in some implementations.


                                Bon, je ne suis pas fan de ce genre de tutos, mais si ça pouvait élaguer 90% des topics inutiles sur le langage C, je ne peux que plussoyer. :)
                                Je pense que tu pourrais rajouter des erreurs/warnings à ta liste. C'est vrai qu'on en avait pas donné beaucoup dans le topic, mais il en reste. :)
                                On pourrait rajouter par exemple error: invalid type argument of ‘->’ ou encore error : invalid initializer. :)
                                Mais faut voir combien tu veux en mettre.

                                Dans la dernière fonction, tu fais 'while(t-tab < taille)', mais tu risques d'avoir un warning ! ahah taille est de type size_t et t-tab de type ptrdiff_t. :p

                                Je le lirai si j'ai le courage. :-°
                                @+
                                • Partager sur Facebook
                                • Partager sur Twitter
                                  31 octobre 2011 à 9:57:03

                                  Citation : Pouet_forever

                                  Tout ce qu'il faut savoir pour les fichiers ouverts en lecture/écriture :



                                  Ça m'était sorti de l'esprit, merci beaucoup !

                                  Citation : Pouet_forever

                                  Bon, je ne suis pas fan de ce genre de tutos, mais si ça pouvait élaguer 90% des topics inutiles sur le langage C, je ne peux que plussoyer. :)


                                  Clairement, il y avait d'autres approches pour traiter le sujet, plus techniques et/ou plus complètes (comme le suggère lmghs). Mais l'idée est bien de cibler spécifiquement les erreurs courantes du forum C, dans l'espoir libérer un peu de place pour les discussions plus techniques.

                                  J'imagine bien que ça ne fera pas de miracles, mais tant pis...

                                  Citation : Pouet_forever

                                  Je pense que tu pourrais rajouter des erreurs/warnings à ta liste. C'est vrai qu'on en avait pas donné beaucoup dans le topic, mais il en reste. :)



                                  Il ne faut pas non plus refaire la documentation de GCC. Cette section est déjà assez conséquente, et c'est la plus « TEA » de tout le tuto. J'espère qu'avec ça, les zéros auront l'idée de comprendre leurs messages eux-mêmes (et non « ce message n'apparaît pas dans le tuto je sais plus quoi faire :( bouh »).

                                  Citation : Pouet_forever

                                  Dans la dernière fonction, tu fais 'while(t-tab < taille)', mais tu risques d'avoir un warning ! ahah taille est de type size_t et t-tab de type ptrdiff_t. :p



                                  Et il n'y a aucune conversion implicite de l'un vers l'autre garantie ? Alors je modifierai en mettant un lien vers la doc. :)
                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                  J'ai déménagé sur Zeste de savoir — Ex-manager des modérateurs.
                                    31 octobre 2011 à 12:37:28

                                    Pour la conversion, si, mais tu auras un joli warning : warning: comparison between signed and unsigned
                                    Comme quoi, les unsigned sont souvent source d'ennuis. :-°
                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                      31 octobre 2011 à 13:20:57

                                      Corrigé.
                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                      J'ai déménagé sur Zeste de savoir — Ex-manager des modérateurs.
                                        31 octobre 2011 à 13:38:56

                                        Citation : Pouet_forever

                                        Pour la conversion, si, mais tu auras un joli warning : warning: comparison between signed and unsigned
                                        Comme quoi, les unsigned sont souvent source d'ennuis. :-°


                                        Marrant, j'aurais dit le contraire!
                                        Vu que sizeof est signed, j'utilise en priorité des size_t et je fais sauter tous les int qui n'en sont pas que je croise.
                                        • Partager sur Facebook
                                        • Partager sur Twitter
                                        C++: Blog|FAQ C++ dvpz|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS| Bons livres sur le C++| PS: Je ne réponds pas aux questions techniques par MP.
                                          7 novembre 2011 à 23:41:40

                                          Moi j'adore ce tuto ! corrige les éventuelles fautes que les pro te signaleront et passe ca en valdiation ! par contre j'aurais bien aimé un QCM bien compelt quand même


                                          --> favoris !
                                          • Partager sur Facebook
                                          • Partager sur Twitter
                                          Anonyme

                                          [Bêta ON] Éviter les erreurs en langage C

                                          × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                                          × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                                          • Editeur
                                          • Markdown