Programme de manipulation de fichiers [Améliorations] - C - Programmation
Marsh Posté le 24-10-2011 à 19:22:04
Bon, j'ai pris une fonction au hasard.
C'est une question de style, mais plutôt que ceci:
Code :
|
J'aurais écrit ceci:
Code :
|
Ou j'ai un seul chemin amenant au succès, et un retour en erreur par défaut.
En plus, ça permet d'avoir des lignes de sens plus clair à la lecture:
if (f = open_file(path, "r" )) { --> Si on a ouvert le fichier ...
La manière dont tu as écrit ton code n'est utile que si tu fais des différentiations sur les types d'erreur rencontrées, et ce n'est manifestement pas le cas de ton code.
Le cast par (void) de le ligne (void) fprintf (stdout, "%c", c); est totalement inutile et à éviter AMHA.
A+,
Marsh Posté le 24-10-2011 à 19:34:55
Salut,
Tout d'abord, merci à toi d'avoir répondu.
Je prend note pour le changement que tu proposes, par contre :
Code :
|
Ce n'est pas un peu répétitif ?
Pour le cast, j'avais lu ça dans des conseils de codage de wikisource, cela permettait de bien tester les retours de fonction. Et puis, splint râle quand je ne caste pas, alors...
Marsh Posté le 24-10-2011 à 19:50:41
Euh, vu que tu ne fais qu’appeler la fonction, sans utiliser la valeur de retour de celle ci, il n'y a aucune raison valable pour qu'un outil râle dans ce cas précis.
Un outil peut râler en cas d'affectation mais ici il n'y en a pas.
Quand à être répétitif, c'est exactement la même chose que dans ton code, mais je préfère un test de boucle simple sans appel de fonction dedans si on peut l'éviter.
Il faudrait profiler pour voir si le code généré est plus efficace, mais ici, c'est plus une question de goût, de préoccupation de lisibilité et de maintenance.
Ce que tu as écrit ici n'a rien de problématique, parce qu'on a des procédure de base bien connues comme fgetc et qu'on sait ce qu'elle fait.
Par contre ce style peut être un peu moins compréhensible avec des procédures maisons dont on n'a pas toujours en tête ce qu'elles renvoient en cas d'échec (en particulier s'il y a plusieurs codes d'échec).
A+,
Marsh Posté le 25-10-2011 à 09:47:39
Citation : Euh, vu que tu ne fais qu’appeler la fonction, sans utiliser la valeur de retour de celle ci, il n'y a aucune raison valable pour qu'un outil râle dans ce cas précis. |
Citation : Une bonne habitude consiste à caster en void tous les appels à des fonctions dont on souhaite ignorer les codes retour. Cette pratique facilite les contrôle avec les outils qualité. [...] Les outils de contrôle statiques comme splint émettent un warning lorsqu'un codes retour de fonction n'est pas testé ou explicitement ignoré. |
http://fr.wikibooks.org/wiki/Conse [...] fication_3
Citation : Quand à être répétitif, c'est exactement la même chose que dans ton code, mais je préfère un test de boucle simple sans appel de fonction dedans si on peut l'éviter. |
En fait, c'est juste que j'ai vu deux fois « fgetc (stdin) » et ça m'a un peu surpris. Pas moyen de faire ça avec un do while ?
Citation : Il faudrait profiler pour voir si le code généré est plus efficace, mais ici, c'est plus une question de goût, de préoccupation de lisibilité et de maintenance. |
Dans ce cas-là, est-il préférable de faire de même avec les conditions ? Aucun appel de fonction dedans ?
Marsh Posté le 25-10-2011 à 11:22:29
Citation : Une bonne habitude consiste à caster en void tous les appels à des fonctions dont on souhaite ignorer les codes retour. Cette pratique facilite les contrôle avec les outils qualité. |
Ça n'a pas grand intérêt sauf éventuellement, à indiquer explicitement à un outil, qui devrait être paramétrable afin de ne pas se préoccuper de ce genre de chose, qu'on ne se préoccupe pas de la valeur de retour. Bref, ça me semble plus être la règle posée pour faire plaisir à un outil et son concepteur qu'autre chose.
Dans la pratique, on ne rencontre pas ce style de cast dans du code C habituellement. Elle est pas complètement idiote donc cette règle, mais comme elle ne fait pas partie des usages, elle risque plus de déconcerter quelqu'un qui relira le code qu'autre chose.
Citation : En fait, c'est juste que j'ai vu deux fois « fgetc (stdin) » et ça m'a un peu surpris. Pas moyen de faire ça avec un do while ? |
A partir du moment ou on exécute le même nombre de fois fgetc (stdin), il vaut mieux avoir un code plus simple et lisible AMHA, en particulier, vis à vis de ce que l'on teste dans sa boucle.
Citation : Dans ce cas-là, est-il préférable de faire de même avec les conditions ? Aucun appel de fonction dedans ? |
On n’exécute la condition qu'une fois, alors c'est moins important, mais ça peut être préférable.
Mais en fait, l'intérêt de ce style, c'est le suivant:
Quand on a:
int (ou char) machin = f(blabla);
if (test sur machin) { bloc (ou on n'utilise pas machin) }
On peut le remplacer par
if (f(blabla)) { bloc }
parce que ça évite une variable inutile.
Idem quand on a:
int (ou char) machin = f(blabla);
while (test sur machin) { bloc (ou on n'utilise pas machin, sauf une fois, pour avoir une nouvelle valeur de test, en faisant machin = f(blabla)) }
On peut le remplacer par
ça se remplace par
while (f(blabla)) { bloc }
Par contre, a partir du moment ou on utilise la valeur testée dans le bloc, on ne gagne rien a utiliser ce style de codage (peut être quelques octets dans l'exécutable généré), et on rend la lecture moins claire.
Pour reprendre ta page exemple,
Citation : while ((optc = getopt_long (argc, argv, "htvm", longopts, (int *) 0)) != EOF) |
Un (bon) programmeur sait à quoi correspond getopt_long, donc il comprends le sens de ce code.
Mais dès que cela devient trop complexe à lire sans perdre le fil du code courant, il vaut mieux éviter, car c'est mauvais pour la maintenance du code.
Un autre point:
FILE *f = NULL;
Il vaut mieux éviter d'affecter a NULL un pointeur déclaré, car alors, le compilateur n'émettra plus les warnings qu'il émet quand un pointeur est utilisé avant d'avoir été affecté, puisque maintenant pour lui, le pointeur a été affecté avant première utilisation, et ça, c'est le genre de warning très utile.
(l'inconvénient c'est que si dans une fonction, on renvoie un pointeur sans l'avoir affecté, la fonction appelante ne peut pas vérifier qu'il n'y a pas eu affectation, mais dans la pratique je préfère ce cas de figure, car quand je récupère un pointeur d'une fonction appellée, je vais relire son code pour vérifier qu'il y a bien eu affectation avant retour de la fonction).
A+,
Marsh Posté le 25-10-2011 à 13:51:27
Merci encore une fois pour ta réponse.
Citation : Ça n'a pas grand intérêt sauf éventuellement, à indiquer explicitement à un outil, qui devrait être paramétrable afin de ne pas se préoccuper de ce genre de chose, qu'on ne se préoccupe pas de la valeur de retour. Bref, ça me semble plus être la règle posée pour faire plaisir à un outil et son concepteur qu'autre chose. |
Si on gagne en lisibilité, je m'avoue vaincu. Mais bon, avec splint :
Citation : file.c:149:3: Return value (type int) ignored: fputs(s, f) |
Citation : On n’exécute la condition qu'une fois, alors c'est moins important, mais ça peut être préférable. |
Après réflexion, je suis tout à fait d'accord.
Citation : Un (bon) programmeur sait à quoi correspond getopt_long, donc il comprends le sens de ce code. |
Je prends note, c'est très intéressant.
Sinon, j'essaie en ce moment de décortiquer une suite de messages de splint :
Spoiler : splint file.c file.c: (in function open_file) |
D'après ce que j'ai déchiffré rapidement, on dirait qu'il ne détecte pas le fclose et donc la libération de la mémoire. Il me parle de memory leak, mais après avoir passé un coup de valgrind, je n'en vois aucune.
Mon file.c :
Code :
|
Merci à tous !
Bonne journée,
lucas-84
Marsh Posté le 24-10-2011 à 17:26:54
Edit : désolé pour l'indentation bizarre, il y a eu un problème lors du c/c... :S
Bonjour,
Je vous présente un petit programme de manipulation de fichiers. Je suis à la recherche de remarques, critiques, etc, vu que je ne programme que depuis un an.
Voici le code :
Merci d'avance et bonne journée à vous tous,
lucas-84
Message édité par lucas-84 le 24-10-2011 à 17:30:18