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

Avatar
espie
In article ,
-ed- wrote:
On 14 mar, 14:14, (Marc Espie) wrote:
In article <C5E16B98.E4589%,
Eric Levenez   wrote:



>Quel serait ton conseil alors ?

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



Impossible dans un projet industriel. Les messages 'ignorés' sont bel
et bien présents dans la liste et peuvent empêcher de voir des
messages importants signalant de vrais problèmes...



Marquer d'une facon ou d'une autre les messages ignores de facon a pouvoir
les filtrer de la liste. Ca revient a avoir une base de donnees des warnings,
et a la mettre a jour a chaque compilation (au besoin avec un peu d'aide de
l'utilisateur, mais bon, entre fuzzer sur le numero de ligne, et faire un hash
du contenu de la ligne plus le message de warning, c'est tres largement
automatisable), puisque ces warnings peuvent bouger un peu, si par exemple
on modifie le code dans ce coin... ou alors trouver un compilateur qui
permette de desactiver un warning precis de facon tres locale a une
instruction du source.
Avatar
Xavier Roche
-ed- a écrit :
Impossible dans un projet industriel. Les messages 'ignorés' sont bel
et bien présents dans la liste et peuvent empêcher de voir des
messages importants signalant de vrais problèmes...



Je conseille de mon côté "dans un projet industriel" l'utilisation de
-Werror (ou ses équivalents): tout avertissement entraine l'échec de la
compilation.

C'est un peu strict, cela demande éventuellement la désactivation
manuelle de certains avertissements un peu stricts, mais au final c'est
très efficace pour améliorer la qualité du code (dans la mesure où les
corrections sont également propres)
Avatar
Jean-Marc Bourguet
Xavier Roche writes:

-ed- a écrit :
Impossible dans un projet industriel. Les messages 'ignorés' sont bel
et bien présents dans la liste et peuvent empêcher de voir des
messages importants signalant de vrais problèmes...



Je conseille de mon côté "dans un projet industriel" l'utilisation de
-Werror (ou ses équivalents): tout avertissement entraine l'échec de la
compilation.



Le problème, c'est que des compilateurs différents ont une idée différente
de quand des warnings sont nécessaires d'une part, d'autre part qu'à partir
d'une certaine taille de projet, on ne recompile pas tout mais qu'on
modularise de manière plus ou moins forte. Résultat ça fait planter le
build sur la plateforme X dans le code de l'équipe Y alors que c'est le
l'équipe Z travaillant sur une plateforme T qui a introduit le problème.

Le choix résulte alors d'un compromis entre le risque qu'un warning reste
ignoré et les problèmes posés par un build cassé sans bonnes raisons.

A+

--
Jean-Marc
FAQ de fclc: http://www.levenez.com/lang/c/faq
Site de usenet-fr: http://www.usenet-fr.news.eu.org
Avatar
Beware
Bonjour a tous,

Après avoir commencé samedi matin, j’ai modifié le code de
mon
pendu. D’abord de légères modifications sur l’application des
règles du jeu,
puis de grosses modifications sur le code en lui-même.
J’espère que ces
dernières rendront le code plus efficace, mais aussi plus correct.

Alors commençons par un retour sur certaines de vos remarques :

Tes fonctions sont trop longues, tu peux decouper plus.
Typiquement, ca se voit bien dans la fonction main(), ou tu
initialises 3 tonnes de variables qui ne te servent pas,
puis passe sur une boucle qui reinitialise les memes variables:
une bonne partie de la boucle devrait etre dans d'autres fonctions.




J'ai corrigé cela, en decoupant ma fonction affichage, celle qui
regroupait le
plus de critique. J'ai également crée d'autres fonctions pour
repondre a des
besoins du programme principal.


Il y a des commentaires inutiles, je pense en particulier a
/* Declaration des variables */
ou le tres inutile:
/* on retourne le choix du joueur */
return (choix_rejouer);
Regle d'or: un commentaire a une valeur ajoutee. Si tu paraphrases
ce que fait le code, sans explication supplementaire, un commentaire
ne sert a rien !



Effectivement, ce commentaire la n'est pas pertinent du tout. En
fait, pour
certains commentaire, j'avoue qu'ils sont plus une aide pour moi qu'un
veritable
apport à la lecture du code.


- c'est dommage de limiter les mots possibles a 10 caracteres, ca me
parait un peu arbitraire.



Tu as raison, c'est vrai que c'est arbitraire. En fait,
c'etait pour me
simplifier les choses au debut du programme. Mais cela peut
etre une
amelioration a apporter sur le plan du deroulement du jeu.


- attention a l'utilisation de fgets() avec un tampon... ca ne marche pas
du tout comme tu penses. le fgets(saisie, sizeof(saisie), stdin) va te
peter a la gueule, surtout avec un tableau de 4 caracteres.
(fgets lit une ligne complete, ou jusqu'a remplir le tableau... elle
ne lit PAS le reste de la ligne... donc si je tape:
34123131311
sur mon clavier, ben je vais me retrouver avec 341 dans mon tampon... et
13131311 en attente sur mon entree standard.
l'utilisation de fgets "propre" est compliquee... :(



J'ai essaye de corriger ce probléme, en vérifiant le retour de la
fonction fgets
et en vidant le buffer stdin pour eviter ces erreurs la. Pour cela je
fais appel
a cette fonction
int c = 0;
while (c != 'n' && c != EOF)
{
c = getchar();
}


- attention aux entrees-sorties sur lignes non completes. printf ne
fonctionne de maniere correcte et garantie QUE si tu affiches une
ligne complete, sinon il peut garder les choses en memoire.
Il faut utiliser setbuf pour changer le mode de tampon, ou fflush
pour etre sur d'afficher avant une entree.
Ton programme marche peut-etre par accident (il y a pas mal de systemes
qui font aussi du C++, et donc qui "attachent" stdin et stdout ensemble),
mais il n'y a rien de garanti.



Sur cette remarque la, j'aurais besoin d'explication parce que je vois
pas
exactement ce que tu veut dire.


- dans les trucs anecdotiques,
#endif // PENDU_H_INCLUDED
peut poser des soucis. Il faut que tu aies un preprocesseur recent pour
que ca marche, les commentaires en // sont issus du C++. Ils sont reconnus
en C maintenant, mais parfois, le preprocesseur n'a pas suivi.



En fait, c'est pas moi qui est mis volontairement cette ligne. J'ai
utilsé la
fonctionnalité de code:blocks pour creer un fichier header, et par
defaut il
ajoute cette ligne.


il y a quelques lourdeurs algorithmiques. Lorsque tu regardes le mot
en cours pour y trouver la lettre jouee... ben tu vois combien d'instances
tu en trouves: tu ne devrais pas avoir a compter les etoiles restantes,
parce que c'est quelque chose que tu peux garder en memoire.
Pareil pour le fichier de mots possibles, tu ne devrais pas avoir a le
relire totalement pour savoir combien il contient de mots.



J'ai corrigé cela en ajoutant des variables supplementaire pour ne pas
a
refaire les boucles a chaque appel de la fonction. mais uniquement
quand
cela me semble necessaire.
Maintenant il peut encore rester des lourdeurs.


- les parentheses de:
((etat_rejouer == REJOUER_MENU) || (etat_rejouer == REJOUER_NORMAL ))
sont inutiles.



Tu as raison, c'est peut etre bete, mais je vois mieux les conditions
comme ca.


J'ai vu moi-aussi ces avertissements, je ne suis pas sur que les corriger
soit une excellente chose. Ici, c'est tout betement lie a des:
if (indice_tableau < strlen(motSecret))



Je n'utilse plus desormais directement strlen dans des conditions. Vu
qu'en plus
cette valeur m'etait utile dans d'autres fonctions, desormais elle
fait partie
des variables disponibles dans une structure.


Le source devrait s'appeler pendu.c
int nb_coup_restant = 0;
int nb_coup_joue = 0;
int nb_coup_max = 0;
Vous allez dire que je suis vieux jeu, mais en français, le qualifiant
d'un compteur doit être au pluriel; donc on préférera nb_coups_resta nts,
etc.
Avec nb_coup_restant, il est possible d'hésiter entre un compteur et un
indice dont le premier terme serait impropre.



J'ai renomé mon fichier main.c en pendu.c et corriger le nom de
certaines
variables.


char lettre;
Un variable de type char est le plus souvent mal typée. En C, une
constante caractère (comme 'a') a pour type int, et ce devrait être le
cas pour les variables qui contiennent des choses similaires. Il y a de
très bonnes raisons (en particulier de pouvoir coder EOF, et de ne pas
perdre bêtement les caractères accentués pour des questions de signe )
pour cela, et le fait d'utiliser char n'a aucun intérêt pratique (cela
ne gagne rien).



Je ne comprends pas cette remarque, il faut que je modifie mes char en
int?


/* Le jeu se deroule tant que le joueur veut rejouer */
do {
...
else if (choix_menu == 3) {
affichage(...);
return (0);
...
}
while((etat_rejouer == REJOUER_MENU) ...
return 0;
Cette boucle est beaucoup trop longue. De plus, la logique de sortie est
trop complexe, c'est en partie lié à l'existence de deux variables,
etat_rejouer et choix_menu. En fait, le return(0) est assez horrible,
c'est un saut déguisé, qui montre un problème de conception géné ral de
l'algorithme qui n'a pas été assez poussée.



La boucle est longue car elle gere le deroulement d'une partie. Et
doit se
repeter autant de fois que le joueur a envie de rejouer. Mais cela
n'empeche pas
un probleme algorithmique. J'ai remplace le return(0) par un exit(0),
mais cela
n'est peut etre pas bon non plus. Ici, le joueur peut choisir de
quitter, et
donc le programme doit cesser immédiatement. Enfin c'est comme ca que
je l'ai
imaginé.


/* Affichage du menu global : */
/* Ce menu permet de : */
/* 1 - lancer le jeu */
/* 2 - ajouter un nouveau mot mystere a la liste disponible */
/* 3 - quitter */
Ce commentaire devrait apparaître devant la fonction et dans le fichier
.h, pas là où elle appelée.



J'ai ajouté des commentaires avant chaque fonction dans le programme
principal,
mais pas dans le header. Cela ne fait il pas trop de repetition si
c'etait
le cas ?

choix_menu = affichage(AFF_GENERAL, nb_coup_joue, ...
Autre utilisation très discutable : la fonction affichage renvoit une
valeur qui n'est jamais utilisée sauf cette fois-là ;



J'ai decoupé les fonctions affichages, et rendu chacune en type void.
Je ne
passe aux fonctions que des pointeurs sur des structures.


motJoue = malloc(strlen(motSecret));
En dehors de la valeur de l'argument (cf. ta première remarque), il faut
utiliser sizeof plutôt que strlen() ici, et calloc() plutôt que
malloc(); voire allouer motJoue en même temps et de la même manière que
motSecret,



J'ai changé l'utilsation du malloc, suivant une autre remarque faite
ici meme,
par l'utilisation d'un calloc :
calloc(partiependu->longeur_motSecret + 1, sizeof(char));


while (motJoue[indice_tableau] != '') {
printf(" %c", motJoue[indice_tableau]);
indice_tableau++;
}
En C, cela s'écrit
printf(" %s", motJoue);



Oui je sais bien. En fait j'ai utilisé - a tort? - cette facon de
faire pour une
raison simple, en utilisant %s j'aurais eu **** alors que je voulais *
* * *.
Voila la raison.


Permettre 4 caractères est une intéressante initiative
(en effet, des lettres comme Œ ou Ç peuvent occuper plusieurs bytes;
mais on préferera MBLEN_MAX), mais elle est n'est pas exploitée par la
suite ; l'utilisation de sscanf est sujette à erreur, par exemple ici si
l'utilisateur tape un espace au début cela va être utilisé comme
proposition...
char saisie[4];
Il n'est pas logique, et potentiellement dangereux, d'utiliser des types
différents pour deux variables qui ont le même nom et à peu près l a même
utilisation.



Quel est l'utilisation de MBLEN_MAX?
Tu as raison, j'ai changé cette valeur pour que toutes les variables
saisie[]
est la meme longueur.


case 1 : choix_niveau = 10;
NON. Il faut écrire
case 1 : choix_niveau = COUPS_FACILE;



Merci, c'est corrigé.


printf( "nt Vous avez perdu. Le mot a trouver etait : %s",
On peut utiliser sans souci les accents dans les messages (sauf si on
s'appelle Marc E. et que l'on travaille sur des terminaux zarbi), c'est
quand même plus lisible.



J'aimerais bien, mais sous la console windows j'ai que des erreurs
d'affichages.
Donc j'ai enleve tous les accents. J'essaye de trouver la bonne
solution pour
contrer cela.


/* On ajoute le nouveau mot */
fprintf(fichier, "%sn", saisie);
Cas typique où il est bon de vérifier la valeur renvoyée par fprintf ().



Corrigé, je controle desormais le nombre de caractére renvoyé par
fprintf()
suivant la longueur du mot a ecrire.


3ème exemple :
------------------------------------------------------------
Il vous reste 2 coups a jouer
Quel est le mot secret? * * E *
Proposez une lettre : U
Il vous reste 1 coup a jouer
Quel est le mot secret? * * E U
Proposez une lettre : b
Le caractere saisi n'est pas une lettre. Seuls
les lettres de l'alphabet sont autorisees.
------------------------------------------------------------
Commentaire : La lettre b minuscule m'a été refusée.



Enfait, dans cet exemple, le probléme vient du fait que tu avais mis
un espace
devant la lettre. J'ai amelioré la saisie en modifiant la fonction
sscanf()
comme ceci :
sscanf(saisie, " %1s", &partiependu->lettre_entest)
Je cherche desormais 1 caractére en ignorant les espaces qu'il peut y
avoir
avant ce caractére.


*) (détail) Fichier d'en-tête assez artificiel ici



Fort possible, je l'ai fait dans le but d'apprendre à les utiliser.


*) (détail) return toto; au lieu de return (toto);



Simple confort visuel pour moi.


*) (peut poser pb) ligne_choisie = (rand() % (nb_mots_disponible - 1) );


et si
nb_mots_disponible==1 ?

Tu as raison, j'ai donc ajouté une etape de controle avec un renvoie
vers la
fonction d'ajout de mot pour avoir au moins 2 mots dans le dico.


*) (à vérifier) Tu es sûr que :
motJoue[indice_tableau] = '';
n'entraîne jamais un débordement ?



Non j'en suis pas sur. Comme, a ce jour, motSecret ne peut exceder 10
lettres,
je cree un tableau motJoue de 11 caractére afin que pouvoir mettre
si le mot
secret fait 10 caractéres.


*) Je trouve ceci curieux :
if (fichier != NULL) {
/* le fichier est bien ouvert */
}
else {
printf( "nt Le fichier dico.txt n'a pu etre ouvert."
"nt Verifiez la presence ou l'intitule du fichier.");
exit(0);
}
Surtout l'accolade vide !! Et exit(0) équivaut à return 0 et c'est la marque
d'une terminaison correcte du programme ("status successful termination" d it la
Norme), or si on n'a pas pu ouvrir le fichier ... Idem plus haut dans ton code
avec le retour de malloc()



Alors, effectivement c'etait un peu bizarre. Un stupide copier-coller
de code.
J'ai donc raccourci a un if.
Le exit(0), est desormais un exit(-1) (et ce aprés le calloc aussi).


Je suis d'accord avec ce qui précède. Je rajouterai qu'il manque aussi
des commentaires. Il faudrait un commentaire en début de fichier pour
expliquer ce que fait le programme, qui l'a écrit, quand, etc. P.ex:
/*
* programme du Jeu de pendu
*
* auteur: Beware
* date: mars 2009
* version: 0.1
*/



Corrigé, merci.


Je suis aussi d'accord avec ça. Ainsi, beaucoup de boucle while()
pourraient être avantageusement remplacer par des boucles for(;;)



J'ai essayé d'en enlever certaines.


Voila, j'ai parfois condenser les remarques qui étaients globalement
les mêmes.



Je vous remercie beaucoup pour toutes ces remarques et vos
encouragements. Et
pour repondre à une remarque :

Oui je suis naturellement doué :)

Non, il est vrai que je suis pas un vrai débutant. Durant mon cursus
universitaire j'ai deja utilsé le langage C mais juste les bases.
Et effectivement, je connais d'autres langages mais pas du tout en
programmtion
pure et dure, je suis ingé electronique et donc j'ai l'habitude
d'utiliser les
langages propres a mon domaine et qui sont un peu éloignés du C. Mais
cela
aide a trouvé une certaines forme de rigeur.

Autre chose, concernant la remarque sur les tabulations excessive, je
reviens
sur un simple confort visuel, j'ai bien que chaques groupes de lignes
qui suit
une accolade ouvrante soit indenté.


Ps :
les fichiers sont mis a jour sur le web :
http://beware007.free.fr/Projet_C/Pendu/
Avatar
espie
In article ,
Beware wrote:
- attention aux entrees-sorties sur lignes non completes. printf ne
fonctionne de maniere correcte et garantie QUE si tu affiches une
ligne complete, sinon il peut garder les choses en memoire.
Il faut utiliser setbuf pour changer le mode de tampon, ou fflush
pour etre sur d'afficher avant une entree.
Ton programme marche peut-etre par accident (il y a pas mal de systemes
qui font aussi du C++, et donc qui "attachent" stdin et stdout ensemble),
mais il n'y a rien de garanti.



Sur cette remarque la, j'aurais besoin d'explication parce que je vois
pas
exactement ce que tu veut dire.




Ma faute, trop de details pas assez de contexte.
Un
printf("Entrez votre valeur: ");
ne va pas forcement afficher quoi que ce soit.
Sur une grosse partie des systemes, les entrees-sorties sont bufferisees pour
eviter d'avoir trop d'appel-systemes, et peuvent se faire "en differe".
La strategie standard pour stdout, c'est de n'afficher reellement quelque
chose qu'en presence d'un retour a la ligne.
Si tu veux afficher des lignes incompletes, il faut rajouter un appel a
fflush:
printf("Entrez votre valeur: ");
fflush(stdout);

- les parentheses de:
((etat_rejouer == REJOUER_MENU) || (etat_rejouer == REJOUER_NORMAL))
sont inutiles.



Tu as raison, c'est peut etre bete, mais je vois mieux les conditions
comme ca.



Manque d'habitude. En tout cas le resultat est peu idiomatique. Il faut
t'habituer a l'idee qu'on ecrit souvent du code de facon standard, et que
tout programmeur C normalement constitue saura le lire sans les parentheses
supplementaires !

Je suis d'accord avec ce qui précède. Je rajouterai qu'il manque aussi
des commentaires. Il faudrait un commentaire en début de fichier pour
expliquer ce que fait le programme, qui l'a écrit, quand, etc. P.ex:
/*
* programme du Jeu de pendu
*
* auteur: Beware
* date: mars 2009
* version: 0.1
*/



Corrigé, merci.



En fait, ca serait encore mieux si tu mettais ton vrai nom, et que tu
mettais une vraie licence d'utilisation sur ton code. Il faudra a un
moment ou un autre te renseigner sur le droit d'auteur et son applicabilite
au code (le vrai nom n'est pas indispensable, c'est juste utile pour eviter
toute contestation).


Pas de remarque sur le nouveau code, j'essaierai d'y jeter un oeil bientot.
Il y a des choses bien, mais c'est encore largement perfectible. ;-)
Avatar
Beware
On 15 mar, 17:35, (Marc Espie) wrote:
In article .com>,

Beware   wrote:
>>- attention aux entrees-sorties sur lignes non completes. printf ne
>>fonctionne de maniere correcte et garantie QUE si tu affiches une
>>ligne complete, sinon il peut garder les choses en memoire.
>>Il faut utiliser setbuf pour changer le mode de tampon, ou fflush
>>pour etre sur d'afficher avant une entree.
>>Ton programme marche peut-etre par accident (il y a pas mal de systemes
>>qui font aussi du C++, et donc qui "attachent" stdin et stdout ensemble ),
>>mais il n'y a rien de garanti.

>Sur cette remarque la, j'aurais besoin d'explication parce que je vois
>pas
>exactement ce que tu veut dire.

Ma faute, trop de details pas assez de contexte.
Un
printf("Entrez votre valeur: ");
ne va pas forcement afficher quoi que ce soit.
Sur une grosse partie des systemes, les entrees-sorties sont bufferisees pour
eviter d'avoir trop d'appel-systemes, et peuvent se faire "en differe".
La strategie standard pour stdout, c'est de n'afficher reellement quelque
chose qu'en presence d'un retour a la ligne.
Si tu veux afficher des lignes incompletes, il faut rajouter un appel a
fflush:
printf("Entrez votre valeur: ");
fflush(stdout);



Donc, si je comprends bien. Je peut continuer a utiliser printf() si
il y a un 'n' dans la chaine (enfin ce qu'il y a entre "") ? C'est
bien ca?
Et si c'est exact faut-il que l'emplacement 'n' soit en fin de chaine
ou pas?



>>- les parentheses de:
>>((etat_rejouer == REJOUER_MENU) || (etat_rejouer == REJOUER_NOR MAL))
>>sont inutiles.

>Tu as raison, c'est peut etre bete, mais je vois mieux les conditions
>comme ca.

Manque d'habitude. En tout cas le resultat est peu idiomatique. Il faut
t'habituer a l'idee qu'on ecrit souvent du code de facon standard, et que
tout programmeur C normalement constitue saura le lire sans les parenthes es
supplementaires !

>>Je suis d'accord avec ce qui précède. Je rajouterai qu'il manque au ssi
>>des commentaires. Il faudrait un commentaire en début de fichier pour
>>expliquer ce que fait le programme, qui l'a écrit, quand, etc. P.ex:
>>/*
>>  * programme du Jeu de pendu
>>  *
>>  * auteur:  Beware
>>  * date:    mars 2009
>>  * version: 0.1
>>  */

>Corrigé, merci.

En fait, ca serait encore mieux si tu mettais ton vrai nom, et que tu
mettais une vraie licence d'utilisation sur ton code. Il faudra a un
moment ou un autre te renseigner sur le droit d'auteur et son applicabili te
au code (le vrai nom n'est pas indispensable, c'est juste utile pour evit er
toute contestation).

Pas de remarque sur le nouveau code, j'essaierai d'y jeter un oeil biento t.
Il y a des choses bien, mais c'est encore largement perfectible. ;-)


Avatar
espie
In article ,
Beware wrote:
On 15 mar, 17:35, (Marc Espie) wrote:
In article


,

Beware   wrote:
>>- attention aux entrees-sorties sur lignes non completes. printf ne
>>fonctionne de maniere correcte et garantie QUE si tu affiches une
>>ligne complete, sinon il peut garder les choses en memoire.
>>Il faut utiliser setbuf pour changer le mode de tampon, ou fflush
>>pour etre sur d'afficher avant une entree.
>>Ton programme marche peut-etre par accident (il y a pas mal de systemes
>>qui font aussi du C++, et donc qui "attachent" stdin et stdout ensemble),
>>mais il n'y a rien de garanti.

>Sur cette remarque la, j'aurais besoin d'explication parce que je vois
>pas
>exactement ce que tu veut dire.

Ma faute, trop de details pas assez de contexte.
Un
printf("Entrez votre valeur: ");
ne va pas forcement afficher quoi que ce soit.
Sur une grosse partie des systemes, les entrees-sorties sont bufferisees pour
eviter d'avoir trop d'appel-systemes, et peuvent se faire "en differe".
La strategie standard pour stdout, c'est de n'afficher reellement quelque
chose qu'en presence d'un retour a la ligne.
Si tu veux afficher des lignes incompletes, il faut rajouter un appel a
fflush:
printf("Entrez votre valeur: ");
fflush(stdout);



Donc, si je comprends bien. Je peut continuer a utiliser printf() si
il y a un 'n' dans la chaine (enfin ce qu'il y a entre "") ? C'est
bien ca?
Et si c'est exact faut-il que l'emplacement 'n' soit en fin de chaine
ou pas?



Si tu rajoutes un fflush() apres chaque printf() qui n'affiche pas une
ligne complete, ca sera bon.

(fflush est standard, cette utilisation est licite, et ca marche).

(et avant que tu demandes, pour un ensemble de raisons complexes, il n'y
a pas d'equivalent pour stdin...)
Avatar
Beware
On 15 mar, 18:11, (Marc Espie) wrote:
In article com>,



Beware   wrote:
>On 15 mar, 17:35, (Marc Espie) wrote:
>> In article
>,

>> Beware   wrote:
>> >>- attention aux entrees-sorties sur lignes non completes. printf ne
>> >>fonctionne de maniere correcte et garantie QUE si tu affiches une
>> >>ligne complete, sinon il peut garder les choses en memoire.
>> >>Il faut utiliser setbuf pour changer le mode de tampon, ou fflush
>> >>pour etre sur d'afficher avant une entree.
>> >>Ton programme marche peut-etre par accident (il y a pas mal de syste mes
>> >>qui font aussi du C++, et donc qui "attachent" stdin et stdout ensem ble),
>> >>mais il n'y a rien de garanti.

>> >Sur cette remarque la, j'aurais besoin d'explication parce que je voi s
>> >pas
>> >exactement ce que tu veut dire.

>> Ma faute, trop de details pas assez de contexte.
>> Un
>> printf("Entrez votre valeur: ");
>> ne va pas forcement afficher quoi que ce soit.
>> Sur une grosse partie des systemes, les entrees-sorties sont bufferise es pour
>> eviter d'avoir trop d'appel-systemes, et peuvent se faire "en differe" .
>> La strategie standard pour stdout, c'est de n'afficher reellement quel que
>> chose qu'en presence d'un retour a la ligne.
>> Si tu veux afficher des lignes incompletes, il faut rajouter un appel a
>> fflush:
>> printf("Entrez votre valeur: ");
>> fflush(stdout);

>Donc, si je comprends bien. Je peut continuer a utiliser printf() si
>il y a un 'n' dans la chaine (enfin ce qu'il y a entre "") ? C'est
>bien ca?
>Et si c'est exact faut-il que l'emplacement 'n' soit en fin de chaine
>ou pas?

Si tu rajoutes un fflush() apres chaque printf() qui n'affiche pas une
ligne complete, ca sera bon.

(fflush est standard, cette utilisation est licite, et ca marche).

(et avant que tu demandes, pour un ensemble de raisons complexes, il n'y
a pas d'equivalent pour stdin...)



Est-ce qu'une macro qui me permette de remplacer ces deux lignes est
une chose "orthodoxe" ou pas? Du genre :
#define PRINT(chaine) printf("%s", chaine);
fflush(stdout);

et ensuite utiliser PRINT quand j'en ai besoin.

La question peut vous paraitre bete, mais comme je n'ai jamais utilisé
les macros je me demande.
Avatar
espie
In article ,
Beware wrote:
Est-ce qu'une macro qui me permette de remplacer ces deux lignes est
une chose "orthodoxe" ou pas? Du genre :
#define PRINT(chaine) printf("%s", chaine);
fflush(stdout);

et ensuite utiliser PRINT quand j'en ai besoin.

La question peut vous paraitre bete, mais comme je n'ai jamais utilisé
les macros je me demande.



Tu n'as jamais utilise les macros: c'est bien, ne commence pas.

Dans ce cas precis, ca n'apporte rien en lisibilite, bien au contraire.

Si tu veux ecrire une fonction, n'hesite pas. Tu peux la marquer comme
etant inline en C99, ce qui te donnera tous les benefices de la macro,
sans aucun de ses inconvenients...
Avatar
JKB
Le 15-03-2009, ? propos de
Re: 1er programme, j'aimerais vos commentaires.,
Marc Espie ?crivait dans fr.comp.lang.c :
In article ,
Beware wrote:
- attention aux entrees-sorties sur lignes non completes. printf ne
fonctionne de maniere correcte et garantie QUE si tu affiches une
ligne complete, sinon il peut garder les choses en memoire.
Il faut utiliser setbuf pour changer le mode de tampon, ou fflush
pour etre sur d'afficher avant une entree.
Ton programme marche peut-etre par accident (il y a pas mal de systemes
qui font aussi du C++, et donc qui "attachent" stdin et stdout ensemble),
mais il n'y a rien de garanti.



Sur cette remarque la, j'aurais besoin d'explication parce que je vois
pas
exactement ce que tu veut dire.




Ma faute, trop de details pas assez de contexte.
Un
printf("Entrez votre valeur: ");
ne va pas forcement afficher quoi que ce soit.
Sur une grosse partie des systemes, les entrees-sorties sont bufferisees pour
eviter d'avoir trop d'appel-systemes, et peuvent se faire "en differe".
La strategie standard pour stdout, c'est de n'afficher reellement quelque
chose qu'en presence d'un retour a la ligne.
Si tu veux afficher des lignes incompletes, il faut rajouter un appel a
fflush:
printf("Entrez votre valeur: ");
fflush(stdout);



Juste une question pour ma culture personnelle. Est-on sûr que
quelque chose va s'afficher lorsque l'argument du printf() contient un
retour à la ligne ? Je me souviens avoir dû coller une macro du type

#define printf(...) { fprintf(stdout, __VA_ARGS__); fflush(stdout); } while(0)

parce qu'un système (de mémoire Solaris ou HP-UX, je ne sais plus)
bufferisait la sortie standard avec des multiples de 1024 octets et que
sur un système chargé, j'avais quelques problèmes... surtout avec les
redirections...

C'est juste une question... Ne pas taper ;-)

Cordialement,

JKB

--
Le cerveau, c'est un véritable scandale écologique. Il représente 2% de notre
masse corporelle, mais disperse à lui seul 25% de l'énergie que nous
consommons tous les jours.