Précédent   Forum du club des développeurs et IT Pro > C et C++ > C > Débuter
Débuter Forum d'entraide pour débuter en langage C. Avant de poster -> FAQ C
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse
 
Outils de la discussion
Publicité
'
Vieux 01/07/2002, 16h42   #1
D[r]eadLock
Membre chevronné

 
Avatar de D[r]eadLock
 
Inscription : mai 2002
Messages : 504
Détails du profil
Informations personnelles :
Âge : 33

Informations forums :
Inscription : mai 2002
Messages : 504
Points : 675
Points : 675
Par défaut Comment bien debugger 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 ]
D[r]eadLock est déconnecté   Envoyer un message privé Réponse avec citation 10
Vieux 02/07/2002, 08h30   #2
gl
Rédacteur/Modérateur
 
Homme
Inscription : juin 2002
Messages : 2 036
Détails du profil
Informations personnelles :
Sexe : Homme
Âge : 34
Localisation : France, Hauts de Seine (Île de France)

Informations forums :
Inscription : juin 2002
Messages : 2 036
Points : 4 027
Points : 4 027
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.
gl est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 03/07/2002, 09h00   #3
D[r]eadLock
Membre chevronné

 
Avatar de D[r]eadLock
 
Inscription : mai 2002
Messages : 504
Détails du profil
Informations personnelles :
Âge : 33

Informations forums :
Inscription : mai 2002
Messages : 504
Points : 675
Points : 675
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.
D[r]eadLock est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 09/10/2002, 01h04   #4
Musaran
Membre actif

 
Inscription : juin 2002
Messages : 97
Détails du profil
Informations forums :
Inscription : juin 2002
Messages : 97
Points : 166
Points : 166
(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 :
1
2
3
4
5
6
7
#include <assert.h>
 
void maFonc(char* pc, int len){
	assert(pc != NULL); //cette fonction ne gère pas le rien, merci !
	assert(len<1000000; //à mon humble avis, ceci n'est pas une longueur de chaîne...
	//...
}

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 :
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 :
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 :
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 :
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 :
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
Musaran est déconnecté   Envoyer un message privé Réponse avec citation 10
Vieux 03/01/2003, 22h31   #5
Fatalis
Nouveau Membre du Club
 
Inscription : décembre 2002
Messages : 29
Détails du profil
Informations forums :
Inscription : décembre 2002
Messages : 29
Points : 30
Points : 30
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 :
assert(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 :
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
Fatalis est déconnecté   Envoyer un message privé Réponse avec citation 11
Vieux 09/02/2003, 16h13   #6
lsdInside
Candidat au titre de Membre du Club
 
Inscription : janvier 2003
Messages : 18
Détails du profil
Informations forums :
Inscription : janvier 2003
Messages : 18
Points : 13
Points : 13
Envoyer un message via ICQ à lsdInside Envoyer un message via MSN à lsdInside Envoyer un message via Yahoo à lsdInside
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 :
1
2
3
4
5
6
7
8
9
10
11
12
Code:
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
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)
lsdInside est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 10/02/2003, 07h58   #7
gl
Rédacteur/Modérateur
 
Homme
Inscription : juin 2002
Messages : 2 036
Détails du profil
Informations personnelles :
Sexe : Homme
Âge : 34
Localisation : France, Hauts de Seine (Île de France)

Informations forums :
Inscription : juin 2002
Messages : 2 036
Points : 4 027
Points : 4 027
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
gl est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 11/02/2003, 06h14   #8
Musaran
Membre actif

 
Inscription : juin 2002
Messages : 97
Détails du profil
Informations forums :
Inscription : juin 2002
Messages : 97
Points : 166
Points : 166
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
Musaran est déconnecté   Envoyer un message privé Réponse avec citation 10
Vieux 11/02/2003, 11h12   #9
gRRosminet
Membre éclairé
 
Homme Thierry
Ingénieur développement logiciels
Inscription : avril 2002
Messages : 121
Détails du profil
Informations personnelles :
Nom : Homme Thierry
Localisation : France

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

Informations forums :
Inscription : avril 2002
Messages : 121
Points : 354
Points : 354
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 !
__________________
lisez les règles
pensez aux tutoriels (les miens)
neXtgen Povray Editor
gRRosminet est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 01/05/2003, 18h35   #10
Metal Tom
Membre habitué
 
Avatar de Metal Tom
 
Thomas P.
Inscription : avril 2003
Messages : 119
Détails du profil
Informations personnelles :
Nom : Thomas P.
Âge : 31

Informations forums :
Inscription : avril 2003
Messages : 119
Points : 110
Points : 110
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
Metal Tom est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 20/06/2003, 15h12   #11
toto_titi
Futur Membre du Club
 
Inscription : mai 2003
Messages : 30
Détails du profil
Informations forums :
Inscription : mai 2003
Messages : 30
Points : 19
Points : 19
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.
toto_titi est déconnecté   Envoyer un message privé Réponse avec citation 10
Vieux 20/06/2003, 15h34   #12
Metal Tom
Membre habitué
 
Avatar de Metal Tom
 
Thomas P.
Inscription : avril 2003
Messages : 119
Détails du profil
Informations personnelles :
Nom : Thomas P.
Âge : 31

Informations forums :
Inscription : avril 2003
Messages : 119
Points : 110
Points : 110
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
Metal Tom est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 20/06/2003, 15h35   #13
Anomaly
Responsable technique

 
Avatar de Anomaly
 
Homme
Administrateur systèmes et développeur Web
Inscription : juin 2003
Messages : 8 032
Détails du profil
Informations personnelles :
Sexe : Homme
Âge : 33
Localisation : France, Somme (Picardie)

Informations professionnelles :
Activité : Administrateur systèmes et développeur Web
Secteur : High Tech - Multimédia et Internet

Informations forums :
Inscription : juin 2003
Messages : 8 032
Points : 22 156
Points : 22 156
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>.
Anomaly est actuellement connecté   Envoyer un message privé Réponse avec citation 10
Vieux 29/01/2004, 16h11   #14
Gnux
Membre Expert
 
Avatar de Gnux
 
Inscription : juillet 2003
Messages : 2 066
Détails du profil
Informations forums :
Inscription : juillet 2003
Messages : 2 066
Points : 2 126
Points : 2 126
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?
Gnux est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 18/03/2004, 09h18   #15
batmatm
Invité régulier
 
Inscription : mars 2004
Messages : 9
Détails du profil
Informations forums :
Inscription : mars 2004
Messages : 9
Points : 6
Points : 6
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 :
monprogramme > /dev/null
@++
batmatm est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 18/03/2004, 09h21   #16
batmatm
Invité régulier
 
Inscription : mars 2004
Messages : 9
Détails du profil
Informations forums :
Inscription : mars 2004
Messages : 9
Points : 6
Points : 6
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)

@++
batmatm est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 19/10/2004, 21h48   #17
Caine
Membre émérite
 
Avatar de Caine
 
Inscription : mai 2004
Messages : 1 020
Détails du profil
Informations personnelles :
Âge : 41

Informations forums :
Inscription : mai 2004
Messages : 1 020
Points : 949
Points : 949
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 :
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
Caine est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 02/03/2005, 18h29   #18
xylo
Candidat au titre de Membre du Club
 
Inscription : mars 2005
Messages : 27
Détails du profil
Informations forums :
Inscription : mars 2005
Messages : 27
Points : 12
Points : 12
juste un complément pour faire de belles traces...

Code :
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: TRACE(("%s", string))
 * ne pas oublier les doubles parenthèses
 *---------------------------------------------------
 */
#ifdef USE_TRACE
# define TRACE(a) do		\
    { printf("TRACE: ");	\
      printf a;			\
      fflush(stdout);		\
      break;			\
    }while(1);
#else
# define TRACE(a)
#endif
et l'utilisation ...

Code :
1
2
 
TRACE(("Error %d : texte %s", err, "Complément"));
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
xylo est déconnecté   Envoyer un message privé Réponse avec citation 10
Vieux 02/03/2005, 20h10   #19
Emmanuel Delahaye
Rédacteur
 
Avatar de Emmanuel Delahaye
 
Inscription : décembre 2003
Messages : 14 505
Détails du profil
Informations personnelles :
Âge : 56
Localisation : France, Paris (Île de France)

Informations forums :
Inscription : décembre 2003
Messages : 14 505
Points : 19 412
Points : 19 412
Citation:
Envoyé par xylo
Code :
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 :
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

Des infos sur la programmation et le langage C:
http://bien-programmer.blogspot.com/
http://www.bien-programmer.fr/
http://bien-programmer.forum-actif.net/forum.htm
Emmanuel Delahaye est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 25/05/2005, 16h12   #20
ylanglais
Invité régulier
 
Inscription : septembre 2004
Messages : 5
Détails du profil
Informations forums :
Inscription : septembre 2004
Messages : 5
Points : 5
Points : 5
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).
ylanglais est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse
Outils de la discussion

Navigation rapide


Fuseau horaire GMT +2. Il est actuellement 22h44.


 
 
 
 
Partenaires

Hébergement Web