IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

 C Discussion :

Comment bien déboguer son code ?


Sujet :

C

  1. #1
    Membre éclairé
    Avatar de D[r]eadLock
    Profil pro
    Inscrit en
    Mai 2002
    Messages
    504
    Détails du profil
    Informations personnelles :
    Âge : 44
    Localisation : France

    Informations forums :
    Inscription : Mai 2002
    Messages : 504
    Points : 750
    Points
    750
    Par défaut Comment bien déboguer son code ?
    Suite a la recrudescence de cas problematique, voici le fruit d'une petite reflexion. Si vous avez d'autre choses a ajouter

    Tout d'abord pour debugger un programme, il faut avoir les idees clair deja quant au programme, c'est a dire :
    - qu'est-ce qu'il fait
    - comment il le fait

    et pour aider a cela, rien de tel que du code clair :
    - indentation (on decale le code de quelques espaces apres un if, etc.)
    - commentaire (telle fonction fait ceci, telle variable contient le resultat, etc.)
    - fractionnement des "fonctions" (faire des fonctions generique plutot que d'avoir une fonction de 150 lignes super chiant a debugger)

    Ensuite, pour les erreurs de compilations,
    - compiler avec le maximum de warnings (-Wall pour gcc). Et comprendre ces warnings : un bon programme ne doit avoir aucun warning : un warning est succeptible de causer une erreur.
    - utiliser man (manuel en ligne pour voir la syntaxe des primitives des librairies) (rappel: 'man fprintf' sous linux/unix), ou l'aide en ligne si disponible.
    - reflechir au sens des instructions : pourquoi on fait ceci, cela etc.

    Enfin, quand vous ne voyez pas l'erreur (et c'est comprehensible), afin de simplifier la tache de ceux qui vont vous aider, il faut specifier au maximum les erreurs rencontrees, en donnant:
    - le message d'erreur,
    - l'environement utilise (win/linux, compilo, librairies...)
    - la ligne du code ou se produit cette erreur
    - le code des structures et autres definitions si besoin est (pour montrer les types des donnees utilisees)

    Il n'est pas necessaire :
    - de donner le code complet (sauf si demande expressement)

    Remarque, lorsque du code est donne, il doit l'etre entre les balises [code ] et [/code ]

  2. #2
    gl
    gl est déconnecté
    Rédacteur

    Homme Profil pro
    Inscrit en
    Juin 2002
    Messages
    2 165
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Juin 2002
    Messages : 2 165
    Points : 4 637
    Points
    4 637
    Par défaut
    Petit complement, non pour debugger (quoique) mais pour limiter le risque de bug :
    - toujours tester les valeurs de retours des fonctions
    - fermer immediatement une accolade puis mettre le code ensuite (ca evite de se retrouver avec un programme qui ne compile pas, et c'est assez penible de tout reprendre pour voir ou se situe le pb)
    - de meme lors d'une allocation, ecrire la ligne de desallocation, puis le traitement entre les deux.

    En passant une petite remarque sur un des conseils de D[r]eadLock :
    "fractionnement des fonctions", c'est une remarque tout a faite vrai dans le cas de la programmation sur PC, mais pour avoir programmer sur des systemes embarques avec rlativement peu de memoire (peu de pile en particulier), le trop grand fractionnement peu etre source dans certains cas de bug memoire (depassement de pile) assez penible a debugger.

  3. #3
    Membre éclairé
    Avatar de D[r]eadLock
    Profil pro
    Inscrit en
    Mai 2002
    Messages
    504
    Détails du profil
    Informations personnelles :
    Âge : 44
    Localisation : France

    Informations forums :
    Inscription : Mai 2002
    Messages : 504
    Points : 750
    Points
    750
    Par défaut
    Pour gvim :
    - set showmatch, pour faire clignoter l'accolade/la parenthese/le crochet ouvrant correspondant quand on en ecrit un/une fermant.

    - % (en mode commande) sur une accolade/parenthese/crochet ouvrant ou fermant pour aller a celui correspondant.

    D'autre part, la syntaxe highlight permet de ne pas trop se planter sur les mots cles, mais surtout, permet de reconnaitre les chaines de caracteres et donc de toutes les fermer.

  4. #4
    Membre averti

    Inscrit en
    Juin 2002
    Messages
    97
    Détails du profil
    Informations forums :
    Inscription : Juin 2002
    Messages : 97
    Points : 307
    Points
    307
    Par défaut
    (quelques notions sont en double avec le premier post)

    D'une façon générale, quand une erreur de compilation ou d'exécution imcompréhensible ne semble pas avoir de rapport avec l'endroit du source où elle survient, elle n'en a effectivement pas et est la conséquence d'une erreur silencieuse précédente.
    Autrement dit, quand le système remarque que quelque chose ne va pas, il est déjà trop tard !

    L'exemple typique pour la compilation est le ";" manquant à la fin d'une struct/class. Très vicieux si elle est dans un header, car l'erreur est signalée dans un autre fichier !
    L'exemple typique pour l'exécution est l'écrasement de mémoire. Par exemple, "char* copie= strcpy(malloc(strlen(source)),source);" oublies le +1 nécessaire au '\0' terminal.


    Pour ne pas faire d'erreurs, le mieux est de comprendre ce que l'on fait (facile à dire).


    Pour éviter les situations indéboguables, le développement incrémental est très bien:
    Cmmencer avec un truc ridiculement simple mais qui marche.
    Rajouter une petite fonctionnalité, tester.
    Rajouter tout le reste pareil: petit à petit, en testant à chaque fois.


    Pour capturer les erreurs, un moyen simple est de protéger son code avec plein d'assertions.
    Elles ne sont actives qu'en mode déboguage.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    #include <assert.h>
     
    void maFonc&#40;char* pc, int len&#41;&#123;
    	assert&#40;pc != NULL&#41;; //cette fonction ne gère pas le rien, merci !
    	assert&#40;len<1000000; //à mon humble avis, ceci n'est pas une longueur de chaîne...
    	//...
    &#125;

    Des nids à erreurs:
    Structures if/else/switch imbriquées trop complexes. Un bogue peut se terrer dans une branche rarement parcourue.
    Fonctions trop longues. Signe que des concepts distincts sont mal indentifiés/séparés.
    Variables utilisées à des endroits très distants. Signe d'inter-dépendance excessive du code.


    L'éditeur est ton ami, il t'aide à ne pas faire de fautes si:
    -Il dispose d'une coloration syntaxique riche.
    -Il propose l'auto-complétion (avec correction majuscule/minuscule please).
    -Il permet de (ré)indenter automatiquement le code.

    Le compilateur se doit de donner des messages d'erreurs compréhensibles, en désignant l'endroit exact où se trouve le problème dans la ligne.
    Régler les alertes au maximum est une bonne pratique.

    Le débogueur est indispensable. Il doît être capable de:
    -Éxécuter le code source pas à pas, en montrant les valeurs des variables et la pile d'appel des fonctions.
    -Gérer des points d'arrêts (conditionnels c'est mieux).
    -Pister les écrasements/fuites de mémoire.

    Un environnement de éveloppement intégré (EDI) regrouppant ces trois-là, plus l'appel de la documentation et d'autres outils, c'est un must !

    La librairie a un rôle à jouer aussi.
    Si elle est de qualité, elle est blindée d'assertions.
    Son interface devrait être intuitive et peu sujette au erreurs.


    Erreurs de débutants fréquentes

    Divers:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    class A{
    }//";" manquant
     
    typedef struct truc truc_t //";" manquant
     
    do{
    	//...
    }while(test) //";" manquant
     
    if(test); //";" en trop (pareil avec for et while)
    	action1(); //pas imbriquée logiquement (à cause du ";")
    	action2(); //pas imbriquée logiquement (il faut englober les deux avec {})
    Erreurs de macros:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #define PI = 3.141596 //erreur: "=" erroné
    double Var = PI*3 ; //Ce code...
    double Var = = 3.141596*3 ; //devient ceci! "syntax error : '='"
     
    #define PI 3.141596; //erreur: ";" erroné
    double Var = PI*3 ; //Ce code...
    double Var = 3.141596;*3 ; //devent ceci ! "illegal indirection"
     
    #define CARRE(a) a*a; //erreur: insuffisant
    int Var3 = CARRE(Var1+Var2) ;//Ce code...
    int Var3 = Var1+(Var2*Var1)+Var2 ;//équivaut à ceci !
    int Var3 = ~CARRE(Var1) ;//Ce code...
    int Var3 = (~Var1)*Var1 ;//équivaut à ceci !
    #define CARRE(a) ((a)*(a)); //corrigé
    Erreurs de syntaxe:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    char* ptr1, ptr2; //erreur: ptr2 est de type char
    char *ptr1, *ptr2; //solution1
    typedef char* charptr;
    charptr ptr1, ptr2;//solution2 
     
    if(Var=EOF) action(); //erreur: "=" au lieu de "=="
    if(EOF=Var) action(); //solution 1, mettre la constante devant provoque une erreur de compilation
    //solution 1, augmenter le niveau de warning
     
    if(/*test*/);
    	/*action*/;
    while(/*test*/);
    	/*action*/;
    for(/*init*/;/*test*/;/*++*/);
    	/*action*/;
    //erreur: ";" termine l'instruction conditionelle sur une instruction nulle.
    //solutions:
    //-réindentation automatique (montre la faute en alignant /*action*/ avec le reste).
    //-augmenter le niveau de warning et mettre "NULL" quand on a vraiment une instruction nulle.
     
    switch (Var) {
    	case 0: /*action*/; //erreur: manque "break"
    	default: /*action*/;
    }
    //solutions:
    //-mettre le commentaire "//no break" quand c'est intentionnel.
    //augmenter le niveau de warning (ne marche pas partout).
    Erreurs de logique:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    int Var2 = Var1+1<<8; //erreur de précédence d'opérateur...
    int Var2 = Var1+(1<<8); //...équivaut à ceci (+256).
    int Var2 = (Var1+1)<<8; //solution: rendre explicite l'ordre si douteux, ou quand on mélange les types d'opérateurs.
     
    int Array[20];
    Array[20] = Var; //erreur: surpassement, tableau de 20 va de 0 à 19.
    Array[i]= i++; //erreur, i peut être incrémenté avant ou après l'indiçage.
     
    char* Msg = "Message";
    Msg[0]= 'm'; //erreur, les chaînes littérales sont des constantes !
    char* cptr = (char*)malloc(strlen(Msg)); //erreur: manque +1 au strlen pour le '\0' terminal.
     
    putchar("A"); //erreur, "A" est une chaîne, 'A' est un caractère
     
    if(/*test1*/)
    	if(/*test2*/){
    		/*action1*/;
    	}; //ce ";" superflu termine le if imbriqué...
    	else //...ce else concerne donc le premier if !
    		/*action2*/;
    Erreurs d'E/S:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    cVar = getchar();
    gets(cArray); //erreur: [Entrée] validant getchar est resté et donne une ligne vide
    while(getchar() != '\n'); //Solution, intercaller ceci pour vider le tampon
    fflush(stdin); //ceci est de comportement indéfini, à éviter !
     
    //idem avec la méthode C++
    cin >> cVar;
    cin.ignore(INT_MAX, '\n');
    cin.getline(cArray,cArraySize);
    "J'ai toujours rêvé d'un ordinateur qui soit aussi facile à utiliser qu'un téléphone. Mon rêve s'est réalisé : je ne sais plus comment utiliser mon téléphone."-Bjarne Stroustrup
    www.stroustrup.com

  5. #5
    Nouveau membre du Club
    Inscrit en
    Décembre 2002
    Messages
    29
    Détails du profil
    Informations forums :
    Inscription : Décembre 2002
    Messages : 29
    Points : 36
    Points
    36
    Par défaut
    petits ajouts et correctifs :

    Citation Envoyé par gl
    toujours tester les valeurs de retours des fonctions
    oui effectivement, mais plus particulierement malloc, surtout ne jamais oublier de tester un malloc, et aussi les file descriptor, toujours tester les open ou fopen et autres...

    Citation Envoyé par gl
    de meme lors d'une allocation, ecrire la ligne de desallocation, puis le traitement entre les deux
    pas necessairement, des fois on veux allouer et ne pas free tout de suite, exemple avec les listes chainers

    il faut juste faire tres attention a la gestion de la memoire

    Citation Envoyé par Musaran
    Par exemple, "char* copie= strcpy(malloc(strlen(source)),source);"
    je trouve ce genre d'ecriture assez dangereuse, et je la deconseille aux debutants, declarez plutot toute vos variables en debut de fonctions, et commencer apres votre code sans ne plus declarer de variables apres, certains compilateurs (GCC le fait) n'autorise plus la declaration de variables apres que des instructions on ete saisie.

    enfin de plus je ne preconise pas l'emploie d'un malloc directement dans une fonction, ceci entraine la perte d'un pointeur et donc une fuite de memoire, pas forcement source d'erreur, mais bon mieux vaut quand meme faire les choses bien.

    il est preferable de separer le code clairement plutot que d'imbriquer trop de fonctions, car ceci peut mener a une erreur de parenthese, voir a une erreur de prioriter dans la gestion du code.

    ...

    Citation Envoyé par Musaran
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    assert&#40;len<1000000; //à mon humble avis, ceci n'est pas une longueur de chaîne...
    tu as oublier la parenthese fermante de ton assert, mais ceci n'est rien, juste un petit signalement

    bon sinon une assez bonne methode de debugging, pour ceux qui travail sur les outils arcailliques, ou pour ceux qui travail sur de bons outils mais qui prefere la methode a la flamme bien moyennageuse la technique du printf debugging est tres bonne, par exemple dans un bout de code qui plante, vous cherchez ou cela plante, tres simple...

    vous placez un printf sur chaques lignes, et cela donne ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    int    ma_fonction(int val)
    {
        char    *str;
     
        printf("1\n");
        str = "crabe";
        printf("2\n");
        str[42] = 'k';
        printf("3\n");
        return (val);
    }
    ainsi vous avez a l'ecran afficher : 1 et 2, ainsi, si vous avez un plantage avant de voir le 3, vous savez tout de suite ou se trouve precisement l'erreur

    voila, pour des questions n'hesitez surtout pas a poster dans le forum
    Fatalis
    "La femme est le chef-d'oeuvre de Dieu, surtout quand elle a le diable au corps" Alphonse Allais

  6. #6
    Membre à l'essai
    Inscrit en
    Janvier 2003
    Messages
    18
    Détails du profil
    Informations forums :
    Inscription : Janvier 2003
    Messages : 18
    Points : 18
    Points
    18
    Par défaut
    Quelques rectificatifs/précisions :

    Citation Envoyé par Fatalis
    je trouve ce genre d'ecriture assez dangereuse, et je la deconseille aux debutants, declarez plutot toute vos variables en debut de fonctions, et commencer apres votre code sans ne plus declarer de variables apres, certains compilateurs (GCC le fait) n'autorise plus la declaration de variables apres que des instructions on ete saisie.
    La norme ANSI C ne prévoit pas qu'il soit possible de déclarer des variables au milieu du code. En C, les variables peuvent être uniquement déclarées juste après une accolade ouvrante. Donc normallement , seul un compilateur C++ compilera du code (C ou C++) contenant des déclarations de variables au sein des instructions.

    Citation Envoyé par Fatalis
    vous placez un printf sur chaques lignes, et cela donne ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    Code&#58;
    int    ma_fonction&#40;int val&#41;
    &#123;
        char    *str;
     
        printf&#40;"1\n"&#41;;
        str = "crabe";
        printf&#40;"2\n"&#41;;
        str&#91;42&#93; = 'k';
        printf&#40;"3\n"&#41;;
        return &#40;val&#41;;
    &#125;
    ainsi vous avez a l'ecran afficher : 1 et 2, ainsi, si vous avez un plantage avant de voir le 3, vous savez tout de suite ou se trouve precisement l'erreur
    Ceci est en effet une bonne habitude à prendre. Mais attention ! La fonction printf est "bufferisée" donc le texte n'est pas immédiatement affiché à l'écran (ou dans le fichier ...). Donc, je pense qu'il est préférable d'utiliser fprintf dirigée sur stderr pour les informations de débogage. (Cette fonction est disponible sous Unix, je ne sais pas si c'est le cas sous DOS/Win)

  7. #7
    gl
    gl est déconnecté
    Rédacteur

    Homme Profil pro
    Inscrit en
    Juin 2002
    Messages
    2 165
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Juin 2002
    Messages : 2 165
    Points : 4 637
    Points
    4 637
    Par défaut
    Citation Envoyé par lsdInside
    Ceci est en effet une bonne habitude à prendre. Mais attention ! La fonction printf est "bufferisée" donc le texte n'est pas immédiatement affiché à l'écran (ou dans le fichier ...). Donc, je pense qu'il est préférable d'utiliser fprintf dirigée sur stderr pour les informations de débogage. (Cette fonction est disponible sous Unix, je ne sais pas si c'est le cas sous DOS/Win)
    fprintf fait partie du C standard donc normalement disponible partout, mais elle est elle aussi bufferisee

  8. #8
    Membre averti

    Inscrit en
    Juin 2002
    Messages
    97
    Détails du profil
    Informations forums :
    Inscription : Juin 2002
    Messages : 97
    Points : 307
    Points
    307
    Par défaut
    Citation Envoyé par lsdInside
    La norme ANSI C ne prévoit pas qu'il soit possible de déclarer des variables au milieu du code.
    En C99 c'est désormais possible.
    "J'ai toujours rêvé d'un ordinateur qui soit aussi facile à utiliser qu'un téléphone. Mon rêve s'est réalisé : je ne sais plus comment utiliser mon téléphone."-Bjarne Stroustrup
    www.stroustrup.com

  9. #9
    Membre confirmé

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2002
    Messages
    137
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2002
    Messages : 137
    Points : 621
    Points
    621
    Par défaut
    Citation Envoyé par gl
    Citation Envoyé par lsdInside
    Ceci est en effet une bonne habitude à prendre. Mais attention ! La fonction printf est "bufferisée" donc le texte n'est pas immédiatement affiché à l'écran (ou dans le fichier ...). Donc, je pense qu'il est préférable d'utiliser fprintf dirigée sur stderr pour les informations de débogage. (Cette fonction est disponible sous Unix, je ne sais pas si c'est le cas sous DOS/Win)
    fprintf fait partie du C standard donc normalement disponible partout, mais elle est elle aussi bufferisee
    L'avantage de stderr est que les les messages sont tout de même affichés même en cas de plantage contrairement a stdout ! cela permet donc de savoir le plantage a réellement eu lieu !

  10. #10
    Membre habitué Avatar de Metal Tom
    Profil pro
    Inscrit en
    Avril 2003
    Messages
    119
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France

    Informations forums :
    Inscription : Avril 2003
    Messages : 119
    Points : 129
    Points
    129
    Par défaut
    Citation Envoyé par gRRosminet
    L'avantage de stderr est que les les messages sont tout de même affichés même en cas de plantage contrairement a stdout ! cela permet donc de savoir le plantage a réellement eu lieu !
    Il me semble que si on fait un fflush(stdout); juste après l'écriture dans stdout ça affiche bien même en cas de plantage (saut si c'est pendant l'écriture dans stdout naturellement).
    Tom

  11. #11
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Mai 2003
    Messages
    30
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2003
    Messages : 30
    Points : 35
    Points
    35
    Par défaut
    Citation Envoyé par Metal Tom
    Il me semble que si on fait un fflush(stdout); juste après l'écriture dans stdout ça affiche bien même en cas de plantage (saut si c'est pendant l'écriture dans stdout naturellement).

    IL y a aussi la fonction C perror() est c'est la simplicite meme pour afficher les messages d'erreurs.

  12. #12
    Membre habitué Avatar de Metal Tom
    Profil pro
    Inscrit en
    Avril 2003
    Messages
    119
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France

    Informations forums :
    Inscription : Avril 2003
    Messages : 119
    Points : 129
    Points
    129
    Par défaut
    Ouais, elle donne plus d'informations sur l'erreur. Elle traduit la variable errno.
    Le message peut être récupéré grâce à sys_errlist[errno]. errno et sys_errlist sont des variables de stdlib.h qu'il faut déclarer (sans oublier le extern) pour les utiliser.
    Tom

  13. #13
    Responsable technique

    Avatar de Anomaly
    Homme Profil pro
    Directeur
    Inscrit en
    Juin 2003
    Messages
    10 333
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Somme (Picardie)

    Informations professionnelles :
    Activité : Directeur
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Juin 2003
    Messages : 10 333
    Points : 130 178
    Points
    130 178
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Metal Tom
    IL y a aussi la fonction C perror() est c'est la simplicite meme pour afficher les messages d'erreurs.
    Oui, mais c'est destiné à afficher le contenu de errno... Or, tu n'en as pas toujours besoin, là il s'agissait de faire une sorte de trace du programme.

    Quant à printf sur stdout, normalement tout \n envoyé vide le buffer... Ceci dit envoyer le message sur stderr permet d'être sûr que le texte sera affiché, car stderr n'est pas bufferisé (c'est une caractéristique du flux d'erreur et non de fprintf), de plus, sous Unix uniquement, il est possible de dissocier la sortie normale du processus de la sortie d'erreur, grâce aux opérateurs de redirection > et 2>.
    Responsable technique forum & site

    Si ce message (ou un autre) vous a aidé et/ou vous semble pertinent, votez pour lui avec

  14. #14
    Membre émérite

    Homme Profil pro
    Inscrit en
    Juillet 2003
    Messages
    2 075
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ardennes (Champagne Ardenne)

    Informations forums :
    Inscription : Juillet 2003
    Messages : 2 075
    Points : 2 844
    Points
    2 844
    Par défaut
    Lut
    Si bien que l'on ne s'est pas quel debugger il faut préférer:Vous utilisez lequel?
    Souos windows comme sous linux?

  15. #15
    Futur Membre du Club
    Profil pro
    Inscrit en
    Mars 2004
    Messages
    9
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2004
    Messages : 9
    Points : 9
    Points
    9
    Par défaut ahhh stderr
    Citation Envoyé par Metal Tom
    Citation Envoyé par gRRosminet
    L'avantage de stderr est que les les messages sont tout de même affichés même en cas de plantage contrairement a stdout ! cela permet donc de savoir le plantage a réellement eu lieu !
    Il me semble que si on fait un fflush(stdout); juste après l'écriture dans stdout ça affiche bien même en cas de plantage (saut si c'est pendant l'écriture dans stdout naturellement).
    stderr est toujours affiché tout simplement parce que cette sortie n'est pas bufferisée, contrairement à stdout C'est effectivement pour cela qu'il vaut mieux envoyer ses messages de debug vers cette sortie. En fait je donnerais meme deux raisons :
    - Vous les voyez immédiatement apparaître à l'écran (et non pas après l'arrivée d'un \n ou un truc du genre pour stdout)
    - Vous pouvez ne garder que les sorties de stderr avec une syntaxe de lancement du genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    monprogramme > /dev/null
    @++

  16. #16
    Futur Membre du Club
    Profil pro
    Inscrit en
    Mars 2004
    Messages
    9
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2004
    Messages : 9
    Points : 9
    Points
    9
    Par défaut debugger
    Citation Envoyé par Gnux
    Lut
    Si bien que l'on ne s'est pas quel debugger il faut préférer:Vous utilisez lequel?
    Souos windows comme sous linux?
    Je ne développe presque jamais sous windows, mais je ne suis pas sûr qu'il existe des debuggers performants existants à la fois sous linux et sous windows.

    J'utilise ddd sous linux qui utilise, je crois gdb. (comme bcp d'autres)

    @++

  17. #17
    Membre éprouvé Avatar de Caine
    Inscrit en
    Mai 2004
    Messages
    1 028
    Détails du profil
    Informations personnelles :
    Âge : 51

    Informations forums :
    Inscription : Mai 2004
    Messages : 1 028
    Points : 1 122
    Points
    1 122
    Par défaut Une méthode éprouvée.
    Bonjour,
    Mon expérience professionnelle et personnelle m’a appris que bien debuguer consiste à prévoir cette phase essentielle dès le départ d’un projet. Voici les trois phases d’un bon debug :

    1) Dés l’étude du cahier des charges, quand on prend connaissance des fonctionnalités de l’application, il est utile de prévoir les tests globaux du projet suivant les contraintes, les objectifs et l’ergonomie de l’application.
    2) Lors de la conception, plus approfondie, mais surtout avant d’avoir les premiers jets de lignes de code, élaborer une vision de l’ensemble des tests unitaires, ainsi que de l’ensemble des tests d’intégration de l’application.
    3) Maintenant les tests listés, commencer à développer les utilitaires de tests.

    Pourquoi se lancer dans l’étude des tests si tôt ? Avant même d’avoir les premières lignes de codes ? La raison est simple : Une fois lancé dans le développement proprement dit, on perd la vision de l’ensemble. Il y a le risque d’oublier des interactions entre modules, ou bien encore carrément de tester certaines valeurs triviales. C’est pourtant sur ces points que l’utilisateur final (un client, un prof…) ne manquera pas de tomber sans forcer le jour J.
    De plus si dés la conception, vous affinez la liste des tests d’intégrations, vous gagnerez du tant lorsqu’un test unitaire échouera au cours de l’évolution du logiciel. En effet, plutôt que de recommencer l’ensemble des tests suite à une correction dans un modules, vous serez quels tests d’intégration rejouer à coup sûr.

    Sans rentrer dans le détail pour ce qui est des tests unitaires (choisir errorno, fprintf avec stderr…), voici quelques conseils :
    1) Ecrire un code clair : Indenter les sources proprement, écrivez des commentaires précis, pertinents et concis (pas besoin de romans).
    2) Tout bloc de code ne servan,t qu’au debug (même la plus petite déclaration) doit être inclus dans un bloc conditionnel.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    #ifdef _debug#else#endif
    3) Vérifier systématiquement les arguments des fonctions et procédures avec des assertions. Si vous connaissez la preuve algorithmique, n’hésitez pas en faire usage.
    4) Préférez des test automatisés à des tests manuels.

    Enfin, une fois cette phase achevée, n’oubliez pas des tests de monter en charge de l’application ou de performance : Charge CPU, Vérifier qu’il n’y a pas de fuites mémoires …

    Bon débug à tous, et toutes

  18. #18
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    27
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2005
    Messages : 27
    Points : 24
    Points
    24
    Par défaut
    juste un complément pour faire de belles traces...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
     
    #define USE_TRACE
     
    /* macro de trace
     * UTILISATION&#58; TRACE&#40;&#40;"%s", string&#41;&#41;
     * ne pas oublier les doubles parenthèses
     *---------------------------------------------------
     */
    #ifdef USE_TRACE
    # define TRACE&#40;a&#41; do		\
        &#123; printf&#40;"TRACE&#58; "&#41;;	\
          printf a;			\
          fflush&#40;stdout&#41;;		\
          break;			\
        &#125;while&#40;1&#41;;
    #else
    # define TRACE&#40;a&#41;
    #endif
    et l'utilisation ...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    TRACE&#40;&#40;"Error %d &#58; texte %s", err, "Complément"&#41;&#41;;
    Ce qui est interessant ici c'est que vous pouvez à la volée préciser votre format pour le printf.

    'Content de peu n'a rien à craindre'
    http://jm.marino.free.fr

  19. #19
    Expert éminent sénior
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Points : 20 985
    Points
    20 985
    Par défaut
    Citation Envoyé par xylo
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    # define TRACE(a) do		\
        { printf("TRACE: ");	\
          printf a;			\
          fflush(stdout);		\
          break;			\
        }while(1);
    C'est pas, c'est sans ';'...

    C'est drôlement compliqué... Tiré de ma bibliothèque:

    http://emmanuel-delahaye.developpez....b/ed/inc/sys.h
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    /* printf programmable (debug)
     * usage : PRINTF (("Hi, I'm %d years old\n", 48))
     */
    #define PRINTF(s)                   \
       printf s
    Pas de Wi-Fi à la maison : CPL

  20. #20
    Futur Membre du Club Avatar de ylanglais
    Homme Profil pro
    Chef de projet en SSII
    Inscrit en
    Septembre 2004
    Messages
    5
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chef de projet en SSII

    Informations forums :
    Inscription : Septembre 2004
    Messages : 5
    Points : 6
    Points
    6
    Par défaut
    Citation Envoyé par Gnux
    Lut
    Si bien que l'on ne s'est pas quel debugger il faut préférer:Vous utilisez lequel?
    Souos windows comme sous linux?
    gdb
    dbx sous solaris quand gdb n'est pas dispo (et que je ne suis pas root).

Discussions similaires

  1. [2.x] Comment bien découper son code ?
    Par jacquesndl dans le forum Symfony
    Réponses: 2
    Dernier message: 29/04/2015, 21h17
  2. [VBA][Excel] Comment bien structurer son code?
    Par skystef dans le forum Macros et VBA Excel
    Réponses: 1
    Dernier message: 15/03/2007, 19h39
  3. comment déboguer son code ?
    Par AdHoc dans le forum Zend
    Réponses: 11
    Dernier message: 05/02/2007, 15h03

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo