Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

[débutant] 1er programme, j'aimerais vos commentaires.

91 réponses
Avatar
Beware
Bonjour,

D=E9butant dans l'apprentissage du langage C, j'ai cr=E9e un petit
programme, un jeu du pendu. Le jeu =E0 l'air de fonctionner. Je dis
"l'air de", car il est probable qu'il reste des bugs que je dois
corriger.
Cependant ce n'est pas l'objet de ma question. En effet, dans un souci
de m'am=E9liorer je d=E9sirerais avoir les commentaires de personnes
connaissant et maitrisant mieux le langage C que moi.

Les fichiers du programme (main.c, pendu.h et dico.txt) sont
disponible ici :
http://beware007.free.fr/Projet_C/Pendu/


Merci d'avance pour votre aide, vos commentaire et critiques.

10 réponses

1 2 3 4 5
Avatar
espie
In article <49bba26a$0$27530$,
candide wrote:
Je trouve ça curieux que pedantic avertisse pour du signé/non signé.



Ambigu: tu trouves curieux d'avoir des avertissement pour signe/non signe,
ou que -pedantic active ces avertissements ?

Dans certaines circonstances, le melange de signe/non signe est un vrai
probleme. Il va forcement y avoir conversion de l'un des operandes, et cette
conversion peut perdre des valeurs. Pire: ca risque de dependre de la
plateforme, et donc etre non portable. Il est donc normal d'avoir des
avertissements dans certaines circonstances.

Le chiendent, c'est qu'avertir systematiquement, ca revient a rajouter du
bruit, parce qu'il y a quand meme un paquet de ces avertissements qui ne
servent a rien. Mais pour pouvoir faire quelque chose de plus intelligent,
il faut une analyse de typage un peu plus fine (typiquement connaitre les
intervalles de valeurs).

Si j'ai:
int a;
unsigned int b;
...

assert(a >= 0);


if (a < b) {
...
}

eh bien je ne devrais pas avoir le moindre avertissement, puisque j'ai deja
verifie que la conversion allait marcher sans perte de valeurs.


Mais ca n'est pas simple.


La liste des avertissements actifs/inactifs dans gcc selon les options change
d'une version a l'autre. Ca n'est pas du tout un probleme simple. Globalement,
ils ont colle dans -pedantic des options qui peuvent etre interessantes, mais
qui contiennent masse de bruit...

-> en general, je n'inclue pas -pedantic dans les options "obligatoires" pour
mes etudiants, precisement a cause des signed vs unsigned.


Il existe plusieurs facons de supprimer ces avertissements. Elles necessitent
toute de regarder attentivement ce qu'on fait, et de bien comprendre les
types non signes en C.

ici, on a un indice compare a une longueur de chaines.
- la pire des "solutions" consiste a caster une des valeurs, par exemple
ecrire
(size_t)indice_tableau < strlen(motSecret)

(tout simplement parce que le cast enleve toute verification de type, et que
indice_tableau pourrait bien etre un pointeur que le compilo n'y verrait que
du feu.

- la 2e solution consiste a declarer indice_tableau en size_t. Ca demande
d'etre certain qu'indice_tableau sera toujours >= 0... ca n'est pas une
transformation mecanique ! il peut y avoir des soucis. Dans les exemples
classiques:

* calcul de distance entre deux valeurs:
delta = abs(a - b);
-> echouera lamentablement des que a-b est calcule en non signe.

* parcours de tableau en ordre inverse:
for (i = sizeof(t)/sizeof(t[0]) - 1; i >= 0; i--)
ne fonctionne plus si i est non signe.


le seul interet de size_t, c'est qu'il permet d'utiliser tout l'eventail
de la memoire disponible. Son equivalent signe, ssize_t, n'est toujours
pas dans ISO C (mais il est dans POSIX), et limite "juste" a la moitie de
la memoire...

Dans la grosse majorite des codes, l'introduction de size_t pour toutes
les tailles memoire est "absurde": il y a d'autres raisons qui font qu'on
sera de toutes facons sur des tailles beaucoup plus petites (dans notre
jeu de pendu, on parle quand meme de la longueur d'un mot ! meme dans les
estimations les plus folles, 80 caracteres devraient suffire...)

Il y a des cas ou c'est utile, bien sur. Si on ecrit une bibliotheque
qui doit se montrer transparente vis-a-vis de la gestion memoire, alors oui,
size_t est indispensable.

C'est pour ca que c'est un vrai avertissement: les comparaisons signes/non
signes doivent etre verifies, et s'il n'y a pas de vrai probleme, on passe
a autre chose... on a toujours un temps limite, qui sera mieux utilise a
corriger de vrais problemes...
Avatar
espie
In article <C5E16365.E4582%,
Eric Levenez wrote:
Le 14/03/09 10:47, dans <49bb7d46$0$21963$,
« candide » a écrit :

Eric Levenez a écrit :

Il conviendrait de corriger ces warnings qui peuvent masquer des problèmes
car size_t est non signé et cela peut entraîner des problèmes dans d'autres
programmes.



Et tu recommandes quoi ? Ne pas utiliser size_t ou caster en int (par exemple)
ou autre chose encore ?





Comme strlen retourne un nombre >= 0, je "casterais" en int le code de
retour de strlen.



Je ne suis pas d'accord avec ce conseil, en terme de methodologie. Rajouter
des cast juste pour faire taire un warning du compilateur est presque toujours
dangereux. C'est un des gros defauts du C, auquel il manque la panoplie de
cast ameliores du C++.
Avatar
Eric Levenez
Le 14/03/09 13:54, dans <gpg9df$d97$, « Marc Espie »
a écrit :

In article <C5E16365.E4582%,
Eric Levenez wrote:

Comme strlen retourne un nombre >= 0, je "casterais" en int le code de
retour de strlen.



Je ne suis pas d'accord avec ce conseil, en terme de methodologie. Rajouter
des cast juste pour faire taire un warning du compilateur est presque toujours
dangereux. C'est un des gros defauts du C, auquel il manque la panoplie de
cast ameliores du C++.



Quel serait ton conseil alors ?

--
Éric Lévénez -- <http://www.levenez.com/>
Unix is not only an OS, it's a way of life.
Avatar
espie
In article <C5E16B98.E4589%,
Eric Levenez wrote:
Le 14/03/09 13:54, dans <gpg9df$d97$, « Marc Espie »
a écrit :

In article <C5E16365.E4582%,
Eric Levenez wrote:

Comme strlen retourne un nombre >= 0, je "casterais" en int le code de
retour de strlen.



Je ne suis pas d'accord avec ce conseil, en terme de methodologie. Rajouter
des cast juste pour faire taire un warning du compilateur est presque toujours
dangereux. C'est un des gros defauts du C, auquel il manque la panoplie de
cast ameliores du C++.



Quel serait ton conseil alors ?



Ignorer l'avertissement et envoyer gcc se faire cuire un oeuf.
Avatar
Eric Levenez
Le 14/03/09 14:14, dans <gpgair$eo2$, « Marc Espie »
a écrit :

In article <C5E16B98.E4589%,
Eric Levenez wrote:
Le 14/03/09 13:54, dans <gpg9df$d97$, « Marc Espie »
a écrit :

In article <C5E16365.E4582%,
Eric Levenez wrote:

Comme strlen retourne un nombre >= 0, je "casterais" en int le code de
retour de strlen.



Je ne suis pas d'accord avec ce conseil, en terme de methodologie. Rajouter
des cast juste pour faire taire un warning du compilateur est presque
toujours
dangereux. C'est un des gros defauts du C, auquel il manque la panoplie de
cast ameliores du C++.



Quel serait ton conseil alors ?



Ignorer l'avertissement et envoyer gcc se faire cuire un oeuf.



Je ne pense pas que ce conseil soit adapté. Comment filtrer les warnings à
traiter de ceux à ignorer ? Tu penses que 20 warnings par source est
acceptable, ou alors c'est 100 ? Peut-être que tu demandes à ton compilateur
d'ignorer tous les warnings et de ne pas les afficher ? Ou alors tu
conseilles d'ajouter ">/dev/null 2>&1" à la ligne de compilation ? :->

--
Éric Lévénez
FAQ de fclc : <http://www.levenez.com/lang/c/faq/>
Avatar
espie
In article <C5E16F90.E4590%,
Eric Levenez wrote:
Je ne pense pas que ce conseil soit adapté. Comment filtrer les warnings à
traiter de ceux à ignorer ? Tu penses que 20 warnings par source est
acceptable, ou alors c'est 100 ? Peut-être que tu demandes à ton compilateur
d'ignorer tous les warnings et de ne pas les afficher ? Ou alors tu
conseilles d'ajouter ">/dev/null 2>&1" à la ligne de compilation ? :->



Non, je conseille de refactoriser un peu le code pour ne pas avoir 25
instances distinctes du meme warning (en fait ici, on en a 4, ce qui est
encore fort raisonnable).

Je suis totalement pour eliminer les avertissements qui peuvent s'eliminer
sans rajouter de problemes supplementaires au code en terme de
maintainabilite.

La plupart des ajouts de cast sont dangereux et peuvent poser des problemes.
Il faut a chaque fois peser le pour et le contre, pour savoir si le cast
est reellement necessaire.

Pour avoir maintenu du code reel pendant suffisamment longtemps, j'ai vu
pas mal de cas ou il aurait mieux valu laisser le warning s'afficher au lieu
de rajouter un cast... une evolution ulterieure du code ayant conduit a
l'introduction d'un vrai probleme de typage, celui-ci etant completement
masque par le cast, et s'etant revele plus tard (lors des test si tout va
bien, en production en l'absence de suite de tests exhaustive).

Apres, on peut militer pour l'amelioration de gcc... entre autres le
rajout d'intelligence dans le compilateur pour eliminer les warnings
debiles...
Avatar
Eric Levenez
Le 14/03/09 13:51, dans <gpg97p$d97$, « Marc Espie »
a écrit :

le seul interet de size_t, c'est qu'il permet d'utiliser tout l'eventail
de la memoire disponible.



Je ne pense pas que la norme parle de cela. Size_t peut stocker la taille
d'un objet, mais cela n'a pas vraiment de rapport avec la taille de la
mémoire RAM et/ou mémoire virtuelle que le programme utilise.

De plus, des valeurs sont à retirer, comme le (size_t)(-1) qui est une
valeur spéciale, d'où un SIZE_MAX toujours plus petit que la taille de la
mémoire. :-)

--
Éric Lévénez
FAQ de fclc : <http://www.levenez.com/lang/c/faq/>
Avatar
Eric Levenez
Le 14/03/09 14:36, dans <gpgbsf$f8e$, « Marc Espie »
a écrit :

In article <C5E16F90.E4590%,
Eric Levenez wrote:
Je ne pense pas que ce conseil soit adapté. Comment filtrer les warnings à
traiter de ceux à ignorer ? Tu penses que 20 warnings par source est
acceptable, ou alors c'est 100 ? Peut-être que tu demandes à ton compilateur
d'ignorer tous les warnings et de ne pas les afficher ? Ou alors tu
conseilles d'ajouter ">/dev/null 2>&1" à la ligne de compilation ? :->



Non, je conseille de refactoriser un peu le code pour ne pas avoir 25
instances distinctes du meme warning (en fait ici, on en a 4, ce qui est
encore fort raisonnable).



4 warnings est raisonnable ? Et à partir de combien tu considères que le
code est mauvais ? 10 ? 100 ?

Je suis totalement pour eliminer les avertissements qui peuvent s'eliminer
sans rajouter de problemes supplementaires au code en terme de
maintainabilite.

La plupart des ajouts de cast sont dangereux et peuvent poser des problemes.
Il faut a chaque fois peser le pour et le contre, pour savoir si le cast
est reellement necessaire.



Le cast que j'ai proposé n'est pas dangereux car il s'applique à une
fonction bien connue et s'applique à des données qui "entrent" dans des int
par construction.

Je ne recommande pas non plus de passer tout en long long dans le cas où les
valeurs soient vraiment grandes.

Pour avoir maintenu du code reel pendant suffisamment longtemps, j'ai vu
pas mal de cas ou il aurait mieux valu laisser le warning s'afficher au lieu
de rajouter un cast... une evolution ulterieure du code ayant conduit a
l'introduction d'un vrai probleme de typage, celui-ci etant completement
masque par le cast, et s'etant revele plus tard (lors des test si tout va
bien, en production en l'absence de suite de tests exhaustive).



Je suis contre les casts en général, mais dans le cas qui nous occupe, c'est
ce que je trouve de plus propre. Passer tout le code en non signé, n'est pas
non plus à conseiller pour tous les problèmes que les non signés posent, en
particulier dans les boucles et les tests. Je suis contre l'utilisation des
variables non signés le plus possible (sauf raison impérieuse) et cela inclu
size_t.

Apres, on peut militer pour l'amelioration de gcc... entre autres le
rajout d'intelligence dans le compilateur pour eliminer les warnings
debiles...



Je considère que les warnings sur les signés/non signés ne sont pas débiles
et doivent être traités et non ignorés.

--
Éric Lévénez
FAQ de fclc : <http://www.levenez.com/lang/c/faq/>
Avatar
candide
Marc Espie a écrit :
In article <49bba26a$0$27530$,
candide wrote:
Je trouve ça curieux que pedantic avertisse pour du signé/non signé.



Ambigu: tu trouves curieux d'avoir des avertissement pour signe/non signe,
ou que -pedantic active ces avertissements ?



Réponse : que -pedantic active ces avertissements

Concernant -pedantic, je trouve qu'il n'est pas évident de savoir quel est son
rôle exact, d'après la doc de gcc, -pedantic avertit chaque fois que la Norme
exige un "diagnostic" :

"to obtain all the diagnostics required by the standard, you should also specify
'-pedantic'"

Après ça faut regarder dans la Norme quand un diagnostic est requis :

5.1.1.3 Diagnostics
1 A conforming implementation shall produce at least one diagnostic message
(identified in an implementation-defined manner) if a preprocessing translation
unit or translation unit contains a violation of any syntax rule or constraint,
(...)

Bref, si on veut savoir, faut avoir en permanence la Norme sous la main.



Dans certaines circonstances, le melange de signe/non signe est un vrai
probleme. Il va forcement y avoir conversion de l'un des operandes, et cette
conversion peut perdre des valeurs. Pire: ca risque de dependre de la



[....]



* calcul de distance entre deux valeurs:
delta = abs(a - b);
-> echouera lamentablement des que a-b est calcule en non signe.

* parcours de tableau en ordre inverse:
for (i = sizeof(t)/sizeof(t[0]) - 1; i >= 0; i--)
ne fonctionne plus si i est non signe.




Je partage totalement ton avis. Quand j'ai commencé le C, je ne connaissais que
les int puis un jour je suis tombé sur size_t et adieu la simplicité. Puis je
suis tombé sur le recommandations dans ce forum concernant l'emploi de size_t
pour des tailles d'objets ou des indices de parcours de tableaux statiques ou
dynamiques. J'ai donc adopté size_t, Puis je suis tombé sur les problèmes de
conversion que tu signales avec les conséquences catastrophiques que cela peut
avoir. Depuis, je suis dans l'expectative, j'ai encore parcouru les archives de
fclc et clc il y a peu de temps à la recherche de la bonne attitude et de la
bonne recommandation.



le seul interet de size_t, c'est qu'il permet d'utiliser tout l'eventail
de la memoire disponible.



L'avantage selon Plauger ("The C standard Library" page 219) est la portabilité.
Mais il met aussi en garde contre les problème de conversion. Il conclut en disant

"The code in this book uses type size_t wherever it is appropriate".



Dans la grosse majorite des codes, l'introduction de size_t pour toutes
les tailles memoire est "absurde": il y a d'autres raisons qui font qu'on
sera de toutes facons sur des tailles beaucoup plus petites (dans notre
jeu de pendu, on parle quand meme de la longueur d'un mot ! meme dans les
estimations les plus folles, 80 caracteres devraient suffire...)



Je suis content que quelqu'un de rigoureux comme toi dise cela, ça va me
décomplexer de ne pas utiliser size_t.
Avatar
Alexandre BACQUART
Eric Levenez wrote:
Apres, on peut militer pour l'amelioration de gcc... entre autres le
rajout d'intelligence dans le compilateur pour eliminer les warnings
debiles...



Je considère que les warnings sur les signés/non signés ne sont pas débiles
et doivent être traités et non ignorés.



C'est juste, mais comme le dit Marc, le cast ne "traite" pas, il fait
taire le compilateur, c'est très différent. Mais dans des cas comme
celui-là, avec des tailles si petites, on voit difficilement quel genre
de problème pourrait survenir à convertir un signé en non-signé.


--
Alex
1 2 3 4 5