Défi: Trouvez les bogues ! (n°42) [C/C++] - C++ - Programmation
Marsh Posté le 05-07-2002 à 02:03:41
Liquidons tout de suite les archétypes...
[B]Erreurs de macros:[/B]
Code :
|
[B]Erreurs de syntaxe:[/B]
Code :
|
[B]Erreurs de logique:[/B]
Code :
|
[B]Erreurs d'E/S:[/B]
Code :
|
...et passons aux choses sérieuses !
Marsh Posté le 05-07-2002 à 02:04:26
Aller hop! J'ouvre le bal.
Celui-ci en a fait tourner en bourrique plus d'un, moi le premier.
[B]Trouvez le bogue !(1)[/B]
Code :
|
Marsh Posté le 05-07-2002 à 02:49:36
bon allez à 3h du mat
je pense que Var1 n'est pas un objet mais la fonction C()
d'où le message
Marsh Posté le 05-07-2002 à 09:31:16
Pareil, les parenthése après la déclaration de l'objet, y en faut pas lorsqu'on appel le constructeur par défaut. Il a interprété la déclaration de Var1 comme le proto d'une focntion.
Marsh Posté le 05-07-2002 à 11:26:48
est ce qu'on a le droit de declarer 2 fois Var2 dans la meme fonction ?
Marsh Posté le 05-07-2002 à 11:28:38
si c pas dans le même bloc ça peut passer:
Code :
|
Ca ça doit passer, et encore pas avec tous les compilos
Marsh Posté le 05-07-2002 à 11:50:15
try58 a écrit a écrit : est ce qu'on a le droit de declarer 2 fois Var2 dans la meme fonction ? |
il s'est juste trompé, faut lire Var4
Marsh Posté le 06-07-2002 à 00:31:36
Bien trouvé !
[B]Solution (1):[/B]
Code :
|
Voilà ce qui arrive quand on a une syntaxe aussi brève que le C++: des ambiguïtés !
ayachi a écrit a écrit : il s'est juste trompé, faut lire Var4 |
Oui, j'avais pourtant fait attention, mais c'est vrai qu'a 3h...
Allez, suivant !
Celui-là est tordu... vraiment tordu !
[B]Trouvez le bogue !(2)[/B]
Code :
|
Marsh Posté le 06-07-2002 à 01:58:36
Code :
|
Ca fait quoi ? (plusieurs réponses possibles)
- ca compile pas
- ca plante
- c'est pas ANSI C++
- ca affiche :
Titi:: print
delete Titi
delete Toto
- ca affiche :
Titi:: print
delete Titi
- ca affiche :
Titi:: print
Toto:: print
delete Titi
delete Toto
- ca fait autre chose
réponse demain
Marsh Posté le 06-07-2002 à 11:15:37
Trouvez l'erreur :
Code :
|
Marsh Posté le 06-07-2002 à 11:18:12
Kristoph a écrit a écrit : Trouvez l'erreur :
|
t'es sur que tu t'es pas trompé de "i" ?
Marsh Posté le 06-07-2002 à 11:38:12
musaran a écrit a écrit : Allez, suivant ! Celui-là est tordu... vraiment tordu ! [B]Trouvez le bogue ![/B]
|
Tu ne connais pas la valeur de EOF : ca pourrait tres bien etre -1.
Marsh Posté le 07-07-2002 à 04:09:21
[B]tanguy (3):[/B]
Un destructeur virtuel pur ?
Je croyais pas que c'était permis, puisqu'un destructeur doit pouvoir être appelé.
Je suppose que c'est non-standard, ou que le standard n'a pas pensé à le préciser.
Quand à la définition d'une fonction virtuelle pure, je sais que c'est possible, mais à priori elle requiert un appel explicite "toto->Toto::~Toto()".
Toujours est-il que "delete toto" tente de libérer l'objet local "titi":
Voici la sortie:
Titi:: print |
Après ça, c'est indéfini.Chez moi ça donne:
delete Titi |
Puis erreur d'assertion.
[B]Kristoph (4):[/B]
Je pense que le i local au for va simplement masquer le i local à main.
Mais je ne peut pas vérifier parce que le compilo Microsoft ne considère pas i local au for.
R3g:
Sois plus clair si tu veux montrer que tu as compris !
Marsh Posté le 07-07-2002 à 12:28:09
Harkonnen a déjà troubé la réponse ( il me semble ), mais je pense que certains n'ont pas compris alors voilà la solution :
Le int i que j'ai définit dans le for n'est absolument pas la même variable que le i réelement utilisé. Celui de main c'est un i normal, celui du for, c'est un i avec un accent.
En fait, cet exemple doit pouvoir marcher même sur VC++ à supposer que votre compilo accepte les caractères ASCII étendus comme identifieurs de noms de variables. Je pense que ça marcherais mieux en Java quand même.
Marsh Posté le 07-07-2002 à 13:02:24
musaran a écrit a écrit : R3g: Sois plus clair si tu veux montrer que tu as compris ! |
Ben EOF est une macro definie dans un fichier d'en-tete.
En faisant while( (ch = getchar()) != EOF) , on suppose que ch =getchar() renverra la valeur de EOF à la fin du fichier. Hors (je crois) getdhar() renvoie 0 si il aucun caractère n'est lu. Cette boucle est donc correcte, à condition que EOF vale 0. Mais EOF peut avoir une autre valeur, comme -1, et getchar() ne renverra jamais -1, d'où la boucle infinie.
Marsh Posté le 07-07-2002 à 13:14:22
Moi je dirais plustot que getchar renvoie non pas un char mais un int et que EOF est défini justement comme étant une valeur ne tenant pas dans un char. Donc en affectant le resultat de getchar à un char, on ne sais plus si getchar a retourné EOF ou un charactère normal.
Marsh Posté le 07-07-2002 à 14:34:05
musaran a écrit a écrit : [B]tanguy:[/B] Un destructeur virtuel pur ? Je croyais pas que c'était permis, puisqu'un destructeur doit pouvoir être appelé. justement ca n'empeche pas qu'il soit appelé Je suppose que c'est non-standard, ou que le standard n'a pas pensé à le préciser. c'est parfaitement standard et défini dans la norme Quand à la définition d'une fonction virtuelle pure, je sais que c'est possible, mais à priori elle requiert un appel explicite "toto->Toto::~Toto()". pour une méthode classique oui, mais pour un destructeur non (voir exeplication plus bas) Toujours est-il que "delete toto" tente de libérer l'objet local "titi":
Après ça, c'est indéfini.Chez moi ça donne:
Puis erreur d'assertion. |
la réponse c'est :
Titi:: print
delete Titi
delete Toto
Segmentation fault
compilé avec gcc 2.95 et gcc 3.1 avec :
g++-3.1 test.cc -lstdc++ -ansi -Wall -Werror -pedantic
c'est du C++ parfaitement ANSI !
Si ca segfault c'est parceque avec delete toto on va supprimer la variable automatique titi et qui sera donc supprimer une deuxième fois automatiquement à la sortie du main.
j'ai mis un delete pour bien faire voir que l'on appellait le destructeur, faut pas se focaliser dessus, d'ailleurs j'aurais pas du le mettre, ca aurait évité que j'écrive 5 lignes pour me justifier lol
donc on peut enlever le delete toto et ca marchera parfaitement sans segfault.
bon alors les explications :
struct Toto
c'est comme une classe sauf que par défaut les données sont public au lieu d'être privé.
Il ne faut pas utiliser struct à la place de class parceque (il me semble) qu'en interne il y a des informations en moins. De toute facon c'était pour le fun il faut toujours utiliser class.
virtual ca veut dire qu'en C++ que l'on veux mettre en place le polymorphisme, et tout le reste tient du polymorphisme.
virtual ~Toto() = 0 signifie que la méthode est virtuelle pure, donc que la classe Toto est abstraite (une interface) et ne peux pas être instancié.
En mettant = 0 on va imposer à celui qui dérive la classe Toto de surdéfinir le destructeur.
Si on n'avait pas mis = 0, dans la classe Titi on aurait pu omettre le destructeur.
voila la seule différence entre virtual et virtual = 0
le programme se comporterai de la meme facon si on avait juste écrit :
virtual ~Toto(); à la place de virtual ~Toto() = 0;
Ca affiche
Titi:: print
à cause du polymorphisme, ca c'est facile
et ca affiche :
delete Titi
delete Toto
également à cause du polymorphisme.
Il faut toujours appeller le destructeur du père, sinon on a une fuite mémoire : le descendant n'est pas correctement détruit.
d'ailleurs si on avait pas mis virtual devant le destructeur de Toto, le compilo affiche (meme cette bouze immonde de Visual C++) :
warning: `struct Toto' has virtual functions but non-virtual destructor
par contre pour une méthode classique en virtual pure, effectivement il faut l'appeler explicitement dans la classe fille. Mais le destructeur c'est un cas particulier comme le constructeur.
d'ailleurs pour s'en convaincre qu'il faut que le destructeur du père soit appeller il suffit de tracer les constrcteurs avec un cout :
on va s'apercevoir que le constructeur du père est systématiquement appellé en premier, puis ensuite celui du fils.
donc il est logique en retour que le destructeur du fils soit appelé en premier puis que le destructeur du père soit appellé.
pour cela il faut que le destructeur du père soit virtual.
par contre y'a un truc qui me choque et que je comprends pas très bien, c'est que l'on ne puisse pas écrire :
virtual ~Toto() = 0 { cout << "delete Toto" << endl; }
mais que l'on soit obliger d'écrire :
virtual ~Toto() = 0;
Toto::~Toto() { cout << "delete Toto" << endl; }
dernière précision :
= 0 ne signifie pas que l'on ne peut pas implémenter la méthode.
Marsh Posté le 07-07-2002 à 18:26:06
Allez, encore une petite. Ca fait quoi ca ?
|
Marsh Posté le 07-07-2002 à 18:35:46
Kristoph a écrit a écrit : Allez, encore une petite. Ca fait quoi ca ? |
Ca prouve a quel point la coloration syntaxique est utile.
Marsh Posté le 07-07-2002 à 18:48:04
Kristoph a écrit a écrit : Allez, encore une petite. Ca fait quoi ca ?
|
Ca fait la somme du contenu d'un tableau (en supposant que ce soit pas un tableau de pointeurs, sinon ca fout la merde).
Marsh Posté le 07-07-2002 à 18:49:49
R3g a écrit a écrit : Ca fait la somme du contenu d'un tableau (en supposant que ce soit pas un tableau de pointeurs, sinon ca fout la merde). |
regarde mieux le commentaire...
Marsh Posté le 07-07-2002 à 18:59:48
lorill a écrit a écrit : regarde mieux le commentaire... |
Ah ouais, j'suis con
Mais en meme temps elle etait bien bien tordue celle-là !
Marsh Posté le 08-07-2002 à 00:30:44
Code :
|
C pas dur
Marsh Posté le 08-07-2002 à 02:20:32
[B]Kristoph[/B] a trouvé le (2).
Quelle est la valeur de l'expression "ch = getchar()" ?
-Les spécifications du C moderne disent: la valeur de ch.
-Beaucoup d'implémentations utilisent le retour de getchar().
Donc ce code risque de marcher... alors qu'il ne devrait pas !
Concernant ta variable "ì", les caractères étendus ne font pas partie du standard C++. En Java si.
(3)tanguy a écrit a écrit : par contre y'a un truc qui me choque et que je comprends pas très bien, c'est que l'on ne puisse pas écrire : virtual ~Toto() = 0 { cout << "delete Toto" << endl; } mais que l'on soit obliger d'écrire : virtual ~Toto() = 0; Toto::~Toto() { cout << "delete Toto" << endl; } dernière précision : = 0 ne signifie pas que l'on ne peut pas implémenter la méthode. |
Parce que le =0 signifie justement qu'il n'y a pas de contenu.
Et puis ça serait une fonction virtuelle inline, ce qui n'est pas de la tarte.
Cela dit c'est accepté par VC++6.
On a vu qu'on peut quand même les définir, mais que cela requiert un appel explicite (précisément pleinement qualifié).
Le destructeur est donc un cas spécial, bénéficiant d'un appel explicite implicite.
Alors là je dis chapeau, ça c'est vraiment tordu.
Ça permet d'écrire un destructeur tout en obligeant une classe dérivée à en fournir un aussi.
Pourquoi pas mettre le destructeur private, pour rire un coup ?
[B](6)MrTonio[/B]:
"void main()" n'est pas standard, c'est "int main()" qui l'est.
A la rigeur, on peut omettre le "return" si le compilateur le permet.
Boucle infinie: i ne vaudra jamais exactement 10, puisque .3 n'est pas un tiers.
Cela reste vrai avec .333333333333333333 ou même 1.0/3.0, en raison de l'aproximation.
Un tout simple maintenant.
[B]Trouvez le bogue !(7)[/B]
Code :
|
Marsh Posté le 08-07-2002 à 21:46:02
musaran a écrit a écrit : Parce que le =0 signifie justement qu'il n'y a pas de contenu. nan justement ! je l'ai dejà écrit, ca signifie simplement qu'il faut obligatoirement redéfinir la méthode dans la classe dérivé (donc la classe de base est abstraite). pas plus, pas moins Et puis ça serait une fonction virtuelle inline, ce qui n'est pas de la tarte. la méthode print() est virtuelle et ca ne lui pose aucun problème pour être aussi en inline Cela dit c'est accepté par VC++6. Visual C++ c'est le pire compilo C++ qui existe. les personnes qui programment avec, pour moi ne font pas du C++ mais de la merde IMHO On a vu qu'on peut quand même les définir, mais que cela requiert un appel explicite (précisément pleinement qualifié). Le destructeur est donc un cas spécial, bénéficiant d'un appel explicite implicite. ba oui, rien de spécial à ca, en C++ le polymorphisme c'est toujours comme ca : le destructeur du père est automatiquement appellé quand on lui ajoint virtual contrairement aux autres méthodes. En C++ le constructeur et le destructeur sont des cas particuliers (ils sont appellés automatiquement, crée automatiquement si on ne le fait pas etc...) Alors là je dis chapeau, ça c'est vraiment tordu. Ça permet d'écrire un destructeur tout en obligeant une classe dérivée à en fournir un aussi. oui ba c'est pas tordu ! en POO on utilise régulièrement des classes abstraites (interface). le destructeur virtuel pure c'est utilisé souvent, mais lui donner une implémentation par défaut beaucoup moins. Pourquoi pas mettre le destructeur private, pour rire un coup ? parceque ca compilera pas, donc c'est pas rigolo |
Marsh Posté le 09-07-2002 à 01:58:31
la méthode print() est virtuelle et ca ne lui pose aucun problème pour être aussi en inline
Ce que doit faire le compilateur n'est pas forcément clair. Une fonction virtuelle doit exister puisqu'elle a un pointeur dans la vtbl. Je suppose que seul un appel pleinement qualifié (Objet.Classe::methode()) sera effectivement inline.
Donc, je me disais que l'écriture "=0 {}" est peut-être évitée pour éviter l'ambigüité.
Visual C++ c'est le pire compilo C++ qui existe.
les personnes qui programment avec, pour moi ne font pas du C++ mais de la merde IMHO
Du code Windows ! (nuance très légère)
Quand je ferais qquechose de sérieux j'en changerait.
parceque ca compilera pas, donc c'est pas rigolo
Je pensais que l'erreur serait à l'endroit de la destruction.
Mais non, il vérifie le destructeur tout de suite.
Marsh Posté le 09-07-2002 à 09:48:54
Visual C++ c'est le pire compilo C++ qui existe.
les personnes qui programment avec, pour moi ne font pas du C++ mais de la merde IMHO
Je suis pas tout à fait d'accord. VC++, l'IDE, l'éditeur est très criticable, puisqu'il est destiner à produire du code windows, donc à priori plus du C que du C++, et qu'il a tous les defauts qu'un produit microsoft peut avoir. Ceci dit, pour faire du code windows rapidement et facilement, il est très adapté, et très performant (l'IDE, pas le code produit).
Quant au compilo lui-même, il est pas mauvais du tout, au contraire c'est sans doute un des meilleurs après le compilo Intel.
Marsh Posté le 09-07-2002 à 20:57:29
R3g a écrit a écrit : Quant au compilo lui-même, il est pas mauvais du tout, au contraire c'est sans doute un des meilleurs après le compilo Intel. |
bon on va recopier ce que j'avais écrit ici :
http://forum.hardware.fr/forum2.ph [...] h=&subcat=
Citation : |
Reveillez-vous les gars, Microsoft c'est la première entreprise mondiale de logiciel avec des milliards de dollars !
ils sont meme pas foutu de faire un compilo qui supportent 2 boucles for d'affilées
faut pas déconner
n'importe quelle compilo C++ est supérieur à VC
que l'on soit obligé d'utiliser Visual C à cause de son boulot je veux bien, faut bien bouffer.
mais défendre cette bouze immonde, c'est de la connerie pure
Vous avez déjà utilisés des VRAIS outils pour la POO ?
Marsh Posté le 10-07-2002 à 09:50:55
tanguy a écrit a écrit : Vous avez déjà utilisés des VRAIS outils pour la POO ? |
Xemacs + GCC, merci pour la convivialité!
Marsh Posté le 10-07-2002 à 10:42:50
Euh, je voudrais pas critiquer, mais avez vous déja essayé VC++ 7 ?
Tous les défauts sus-mentionnés ont disparu comme par enchantement...
Marsh Posté le 10-07-2002 à 21:09:41
Harkonnen a écrit a écrit : Euh, je voudrais pas critiquer, mais avez vous déja essayé VC++ 7 ? Tous les défauts sus-mentionnés ont disparu comme par enchantement... |
T'arrives à faire ca avec ton visual de merde ?
http://tanguy.dyndns.org/~tanguy/together3.gif
http://tanguy.dyndns.org/~tanguy/together1.gif
http://tanguy.dyndns.org/~tanguy/together2.gif
Et la version 7 elle supporte export, les string stream ?
on peut avoir des warnings (oui parceque pour le moment j'appelle meme pas ca des warnings) ?
Ca affiche autre chose que de l'assembleur quand on fait un trace de trop, ou il faut encore mettre un patch ?
Pour moi visual est une bouze et le restera, je vois pas pourquoi ca changerait (ils sont eu des années + plein de fric pour le faire).
Le seul truc qui fait jouir les blaireaux c'est la complétion de visual. Forcément quand on voit l'API du SDK, c'est tellement mal foutu que sans la complétion ca serait impossible à utiliser...
bon on va s'arreter là...
Je n'arriverais pas à convaincre quelqu'un que c'est de la merde et qu'il existe des produits 20x mieux, tant au niveau IDE que compilateur.
Marsh Posté le 10-07-2002 à 21:30:39
J'ai déja remarqué que ceux qui utilisent visual on commencé avec et n'ont jamais utilisé autre chose sans y etre forcé
Marsh Posté le 10-07-2002 à 21:31:08
tanguy a écrit a écrit : T'arrives à faire ca avec ton visual de merde ? http://tanguy.dyndns.org/~tanguy/together3.gif http://tanguy.dyndns.org/~tanguy/together1.gif http://tanguy.dyndns.org/~tanguy/together2.gif Et la version 7 elle supporte export, les string stream ? on peut avoir des warnings (oui parceque pour le moment j'appelle meme pas ca des warnings) ? Ca affiche autre chose que de l'assembleur quand on fait un trace de trop, ou il faut encore mettre un patch ? Pour moi visual est une bouze et le restera, je vois pas pourquoi ca changerait (ils sont eu des années + plein de fric pour le faire). Le seul truc qui fait jouir les blaireaux c'est la complétion de visual. Forcément quand on voit l'API du SDK, c'est tellement mal foutu que sans la complétion ca serait impossible à utiliser... bon on va s'arreter là... Je n'arriverais pas à convaincre quelqu'un que c'est de la merde et qu'il existe des produits 20x mieux, tant au niveau IDE que compilateur. |
c fort joli mais pkoi est ce qu'on pourrait pas faire ca avec visu ?
Marsh Posté le 10-07-2002 à 21:36:39
chrisbk a écrit a écrit : c fort joli mais pkoi est ce qu'on pourrait pas faire ca avec visu ? |
vc il peut pas tracer des lignes et carrés à la con
Marsh Posté le 10-07-2002 à 21:38:07
youdontcare a écrit a écrit : vc il peut pas tracer des lignes et carrés à la con |
pardon ?
Marsh Posté le 11-07-2002 à 08:27:58
Ouai enfin si c juste que tu peux pas faire de diagramme UML c pas top grave, Visual a des lacunes plus graves je trouve
Marsh Posté le 11-07-2002 à 09:25:07
Tanguy > t'as déja entendu parler de Visio ?
Citation : J'ai déja remarqué que ceux qui utilisent visual on commencé avec et n'ont jamais utilisé autre chose sans y etre forcé |
Tout a fait ! J'ai commencé le C++ sous Windows avec Visual C++ 4, mais dans le cadre de mes loisirs.
Au boulot, j'utilise C++ Builder, mais j'y suis forcé.
VC++ a des défauts, c'est clair. Tous les IDE en ont. Mais le critiquer parce que c'est du Microsoft, la désolé mais je suis pas d'accord. Le VC++ 6 était buggé à mort, mais le .NET a bien rectifié le tir.
Marsh Posté le 11-07-2002 à 13:14:06
Harkonnen a écrit a écrit : Tanguy > t'as déja entendu parler de Visio ?
|
Exact, meme la sp6 de vc me plante des fois encore a la gueule au moment de la compilation (il met 2 ans a sauvegarder un pauvre fichier, pis apres, prout). Le net corrige ces genres de conneries ?
Marsh Posté le 11-07-2002 à 14:11:39
[
musaran a écrit a écrit : [B]Kristoph[/B] a trouvé le (2). Quelle est la valeur de l'expression "ch = getchar()" ? -Les spécifications du C moderne disent: la valeur de ch. -Beaucoup d'implémentations utilisent le retour de getchar(). Donc ce code risque de marcher... alors qu'il ne devrait pas ! |
Ben je dirais que c'est bon parce que:
dans le cas 1 : retour de la valeur de ch, ch etant definis comme
char et donc signe', et EOF = -1 donc la conversion est correct.
dans le cas 2: trivial !
en fait il aurait fallu declarer unsigned ch ... et la boucle infinie !
Plucker
Marsh Posté le 05-07-2002 à 02:02:46
Je vous invite à un nouveau jeu:
Trouver le bogue dans un bout de code, ou proposer un tel code bogué.
J'apelle bogue toute erreur/mauvaise utilisation qui fait, ou peut faire, que le code ne compile pas, ne linke pas, ou que l'exécutable ne marche pas comme voulu.
Autrement dit, la palette est large...
C'est plus drôle si:
Pour être plus clair, je propose:
Message édité par Musaran le 29-12-2002 à 05:16:35
---------------
Bricocheap: Montage de ventilo sur paté de mastic silicone