Je suis en train de vérifier si j'ai bien free tous mes mallocs dans mon programme mais j'ai un petit doute sur quelque chose si quelqu'un peux m'expliquer svp.
imaginons que j'ai une fonction qui retourne un char *, que j'ai precedent malloc ex :
char *fonction (int a, char *str)
{
char *s;
s = NULL;
s = malloc(sizeof(char) * 10);
if (a == 1)
return(NULL);
if (a == 2)
{
s = strncpy(s, str, ft_strlen(str);
return(s);
}
}
et que j'appel cette fonction de cette maniere :
int main ()
{
if (fonction(2, "salut"));
printf("salut");
else
printf("bonjour");
return(0);
}
Le main appel la fonction pour voir si ca retourne quelque chose ou si ca retourne null.
Sauf que la fonction a créer un malloc, mais que je ne peux pas free. il aurait fallu que je le stock dans une variable en faisant :
char *x;
x = fonction(2, "salut");
if (x != NULL)
printf("salut");
else
printf("bonjour");
Ma question est donc de savoir si je peux faire comme dans le premiere main ou pour pouvoir free, je suis obligée de faire la deuxième soluce ? si je peux faire la premiere, est ce que j aurai un probleme de leaks ?
Puisqu'en C la taille est exprimée en nombre de chars.
Un peu de logique : si on a une fonction dont le but est de retourner un truc alloué dynamiquement, il faut garder une trace du résultat en le notant quelque part. Et ça permettra de le frire si tu as envie à l'huile, à la margarine, peu importe.
- Edité par michelbillaud 22 février 2021 à 17:26:16
Toujours le sizeof(char) qui traine un peu partout. Et la margarine, c'est pour aller avec le béton à la farine de White Crow? Même si c'est rare qu'on a le problème, il faudrait vérifier que malloc retourne bien un pointeur non NULL. Si on ne sais pas toujours où on est rendu quand on fait le free() ... Il faudrait vérifier avant de le faire que le pointeur est non NULL (il peut être faux, mais c'est une autre histoire ...) et ensuite mettre le pointeur à NULL après le free().t
Le Tout est souvent plus grand que la somme de ses parties.
Je suis en train de vérifier si j'ai bien free tous mes mallocs dans mon programme mais j'ai un petit doute sur quelque chose si quelqu'un peux m'expliquer svp.
[...]
Hello,
il existe des outils comme valgrind qui t'aident à lever les doutes … savoir s'en servir (memory profiler, debuger, profiler, …) est une compétence inestimable.
En attendant, oui ton code est hyper mal foutu !
char *fonction (int a, char *str)
{
char *s;
s = NULL;
s = malloc(sizeof(char) * 10);
if (a == 1)
return(NULL);
if (a == 2)
{
s = strncpy(s, str, ft_strlen(str);
return(s);
}
}
Pue importe la valeur de a, il y aura une allocation mémoire. Mais le résultat de cette allocation ne sera communiquée à l'extérieur de la fonction que lorsque a vaudra 2. Si a vaut 1, on renvoie NULL ⇒ le bloc alloué ne pourra plus être libéré par un free !!!! pas bon !!!!!
Mais il y a pire !!!! Si a ne vaut ni 1 ni 2 que se passe-t-il ? …
Ce genre de code est forcément source de bugs.
char *fonction (int a, char *str)
{
char *s=NULL;
if (a == 2) {
s = malloc( ft_strlen(str) + 1 );
if (s!=NULL)
ft_strcpy(s, str);
}
return s;
}
Ce code est un peu plus compact et surtout correct. Tous les chemins renvoient une valeur, et il n'y a une allocation que si une valeur non NULL est renvoyée et cette valeur sera celle du début du bloc alloué.
Très personnellement, plus que l'utilisation du sizeof(char) c'est l'utilisation du keyword return (entre autre) comme une fonction qui me fait saigner les yeux dans la norme.
Je vais faire une premiere réponse, je n'ai pas dit que ce code compilait, j essai de faire un exemple pour que ce soit claire, et eviter dque vosu ayez a checker un code complet pour uin question d'ordre generale.
Je suis a 42, je ne peux pas initialiser en même temps que je déclare car je dois suivre leur norme.
Mon projet c'est un minishell, je n'arrive pas a faire passer valgrind dessus, j'avoue que je n'ai pas essayé de trouver pourquoi, car j'en suis pas encore à ça.
J ai expliqué que ce code EST A TITRE D EXEMPLE pour illustrer ma question.
LA fontion avec laquelle je me pose cette question me sert a recuperer une chaine generale mais je l utilise aussi parfois pour verifier si elle renvoi quelque chose.
Je n utilise pas de a == 1 ou a ==2, je ne retourne pas de cette maniere, ce code est encore une fois un titre d exemple pour que vous compreniez ma question.
Je verifie bien que les mallocs n'ont pas échoué non plus.
Je vais mettre mon code pour éviter les moqueries et la condescendance puis ensuite je lirai les réponses que vous m'avez faite et qui réponde a ma question. je vous en remercie.
Je vais faire une premiere réponse, je n'ai pas dit que ce code compilait, j essai de faire un exemple pour que ce soit claire, et eviter dque vosu ayez a checker un code complet pour uin question d'ordre generale.
Ce qui est top Et la réponse est claire : si tu fais un malloc dans une fonction, que ce malloc n'échoue pas alors il faut impérativement communiquer la valeur de retour du malloc à l'extérieur de la fonction pour pouvoir faire un free dessus.
Si tu as des mallocs sans free ce sont des fuites de mémoires irrémédiables !
c'est le sens de mon intervention :
«Tous les chemins renvoient une valeur, et il n'y a une allocation que si une valeur non NULL est renvoyée et cette valeur sera celle du début du bloc alloué.»
marioonb a écrit:
Mon projet c'est un minishell, je n'arrive pas a faire passer valgrind dessus, j'avoue que je n'ai pas essayé de trouver pourquoi, car j'en suis pas encore à ça.
[...]
-
Edité par marioonb il y a moins de 30s
Et pourtant ça t'aiderait énormément … il vaut mieux avoir les mauvaises nouvelles le plus tôt possible pour pouvoir corriger les tirs !
Prendre le temps d'apprendre à utiliser valgrind ne sera jamais un perte de temps. D'autant plus que ça se résume bien souvent à :
avec exe_a_tester ayant été compilé en mode debug, bien évidemment. Tu testes les chemins dans ton exe et tu as directement tous les problèmes mémoires … magique et indispensable !
marioonb a écrit:
Je verifie bien que les mallocs n'ont pas échoué non plus.
[...]
Pas tous 👿
marioonb a écrit:
Je suis a 42, je ne peux pas initialiser en même temps que je déclare car je dois suivre leur norme.
[...]
Bah ouais … pas de bol … une norme pas très adaptée mais oui, tu dois la suivre ; et nous comme d'hab on la critique ^_^
Super je te remercie pour ta réponse et ces précisions, en fait tout est un problème de norme et c'est pénible... Nous ne pouvons faire que 25 lignes et donc cette façon de faire me permet de gagner des lignes, parce qu'encore une fois à cause de la norme, si je veux stocker le retour, ça me prend 3 lignes supplémentaires... du découpages de fonction qui n'ont aucun sens et le temps qui va avec...
J'ai espéré qu'il y ait une solution mais du coup d'après ta réponse et celles des autres, je ne pense pas.
Concernant valgrind j'utilisais --leak-check=full –track-origins=yes sur mes autres projets déjà, mais pour celui ci, impossible de faire tourner valgrind même sans flag...
Tu as raison je devrais m'y pencher un peu plus mais c'est surtout par manque de temps que je ne le fais pas, meme si au final ca peut m'en faire gagner, voilà avec ta commande, ce que j ai :
et ça reste comme ça... ça ne me donne rien de plus, je suis pas très calée au niveau de valgrind et ça me semble une montagne de trouver d'ou vient le problème... Du coup je pensais que c'était peut être du au type de projet, puisqu'il attend des commandes sur STDIN. Tu me dit de tester en mode debug, mais je t'avoue que je ne sais pas ce que tu entends par la. Peut être as tu une réponse à m'apporter ?
En effet je ne vérifie pas mon malloc de pwd2, je te remercie car j'ai verif ne comprenant pas ta remarque et en fait cette ligne n'a rien a foutre là, encore à cause de la norme j ai du découper cette fonction et le malloc se fait dans concat_for_change(j ai plus d'inspi pour les noms lol), j ai du oublié de le supprimer, une erreur de moins à chercher lol.
Et tu fais bien de critiquer la norme, autant elle nous permet de la rigueur, autant parfois elle n'est en effet pas adaptée...
As-tu affaire à un prof qui vous fait payer à la ligne la publication de votre code? Ce n'est pas une moquerie contre toi, mais contre ton prof. Je pourrais dire que tu avais utilisé 3 lignes pour faire ce qui se fait en 1 ligne: char *s = malloc(10); // pas besoin d'initialiser à NULL avant. et pourquoi ne pas vérifier la longueur de la chaîne que tu vas recopier "avant" de faire le malloc et réserver la bonne grandeur en n'oubliant pas la fin de chaîne.
Le Tout est souvent plus grand que la somme de ses parties.
Le respect de norme à la con, c'est pas de la rigueur, mais de la discipline. Vous ne faites pas ce que le chef vous interdit de faire, sans discuter, même si ça serait mieux.
La rigueur, c'est pas l'application d'une consigne externe. Ça consiste à faire attention, à avoir un regard critique constamment, et du soin pour arranger les choses quand on sent qu'on peut faire mieux.
Quand valgrind ne se lance pas, revoir les commandes de compilation et d'édition des liens. Les options utiles (-g avec gcc) y sont elles ?
- Edité par michelbillaud 23 février 2021 à 7:15:58
J'ai déjà parlé de mon principe «de la balle de tennis» La balle ne peut pas être des deux coôtés du filet en même temps. En fait, l'idée est de ne garder qu'un pointeur sur une zone allouée par malloc ou une autre ressource. Si tu trimbales des pointeurs n'importe où sans savoir ce qu'ils contiennent, tu cours à l'échec. On ne devrait même pas à faire ce que j'ai dit: vérifier si le pointeur est NULL avant le free() et le mettre à NULL après.
Le Tout est souvent plus grand que la somme de ses parties.
[...] Concernant valgrind j'utilisais --leak-check=full –track-origins=yes sur mes autres projets déjà, mais pour celui ci, impossible de faire tourner valgrind même sans flag...
Tu as raison je devrais m'y pencher un peu plus mais c'est surtout par manque de temps que je ne le fais pas, meme si au final ca peut m'en faire gagner, voilà avec ta commande, ce que j ai :
et ça reste comme ça... ça ne me donne rien de plus, je suis pas très calée au niveau de valgrind et ça me semble une montagne de trouver d'ou vient le problème...
Alors parfois le plus simple est de chercher le message d'erreur sur le net, en l'occurrence «unknown task message». En lisant en diagonale les pages intéressantes, on apprend qu'il s'agit d'un problème d'instabilité de cette version de non mainstream de Valgrind sur Mac, ou quelque chose dans le genre. Il est conseillé d'utiliser la version de mainstream de valgrind … https://www.valgrind.org/downloads/repository.html
Je ne connais pas l'environnement mac, mais peut être qu'une âme charitable ici pourra t'aider ? je suppose que lui donner la version de valgrind utilisée (valgrind --version), ta version de mac, comment tu as installé valgrind, … seront des infos utiles.
marioonb a écrit:
Tu me dit de tester en mode debug, mais je t'avoue que je ne sais pas ce que tu entends par la. Peut être as tu une réponse à m'apporter ?
-
Edité par marioonb il y a environ 9 heures
La même que Michel
michelbillaud a écrit:
Quand valgrind ne se lance pas, revoir les commandes de compilation et d'édition des liens. Les options utiles (-g avec gcc) y sont elles ?
- Edité par michelbillaud il y a environ 1 heure
Il faut compiler ton projet en mode debug, cela signifie en général l'utilisation du flag -g lors de la compilation, et surtout ne pas mettre de flag -O (moins grand oh) ⇒ cela produit une version de l'exécutable avec les infos de debug sans optimisation. Les infos de debug permettront, entre autre, à valgrind de te dire où se produit l'erreur, à quelle ligne de code tu malloc de la mémoire que tu ne free pas, …
Pierrot le fou : Je n'ai pas de prof mais mes projets à rendre sont soumis à une norme, je ne peux malheureusement la contourner. Alors oui en effet, pour ce type de déclaration c'est assez relou. C'est pareil pour check la longueur de la ligne avant, ça me fait une ligne en moins de faire comme je fais. Concernant le fait de remettre le pointeur a NULL après le free, je le fais parfois, j'ai justement essayé de me documenter la dessus, mais il semble qu'il ne faille pas le faire dans tous les cas, pour des raisons que je n'ai pas bien comprises, du coup j'hésite à le faire partout... Mais peut être que tu en sais plus sur le sujet pour pouvoir m'éclairer.
MichelBillaud, quand je parle de rigueur, je parle plutôt du reste, l'indentation, l'utilisation des variables, la structure du projet etc... La norme 42 ce n'est pas seulement les 25 lignes, alors oui ça me permet d'avoir une certaine rigueur, parfois je vois des codes, c est une cata, illisibles. Ya des choses bonnes et mauvaise a prendre dans la norme de 42, les 25 lignes ça évite les fonctions interminables et dans certains cas c'est trop strict, concernant les déclarations de variables ça nous évite de les déclarer à n'importe quel endroit, quand on à leur initialisation on est d'accord, c est pas ce qu'ils ont trouvé de mieux.
Je précise que tous nos projets passent par un programme qui vérifie si il est normé... si ce n'est pas le cas c'est 0, donc je ne peux même pas débattre avec eux sur le sujet, le plus important pour moi est de passer le projet à 100% que je sois d accord avec leur norme ou non.
Pour le lenght oui sorry, tu me l'a deja dit en plus lol. Je vais faire plus attention, généralement, je renomme après mais la ce projet est interminable.... Pour la fonction exec_chdir, suite au post de de white crow, c'est celle la que j ai changé, car c'est une erreur en voulant la découper, en fait elle est comme cela :
Je n ai pas le droit d utiliser get_env et set_env... mais c'est vrai que je l'ai fait un peu à ma sauce mais je vais check ces deux fonctions pour essayer de m'en inspirer et les réécrire, la partie de mon shell pour le builtin CD, n'est pas encore totalement terminé, mais je prend tes remarques en note, je te remercie.
oui pour le -g sorry, biensure que je l'ai mis, je pensais que lorsque vous avez évoqué le mode debug c'était encore une autre façon de faire, mais en effet j'aurai du penser que vous parliez du flag -g qui est donc bien mis.
White crow, merci je vais check pour mettre une autre version, franchement je me souviens plus comment je l'ai installé ça date et j'avais du suivre un tuto, a l'époque j'étais pas vraiment a l'aise encore, j'ai peut être pas pris la bonne version. En tous cas ça a toujours marché sur mes autres projets, je vais check ça pour une autre version. L'actuelle est : valgrind-3.17.0.GIT. Je n'utilise pas le flag -O, juste -Wall -Wextra -Werror -fsanitize=address -g3...
Merci pour vos réponses pertinentes et constructives en tous cas...
oublie le fsanitize=address !!!! cela va interférer avec valgrind …
Quand tu utilises cette option, ton exécutable va embarquer un code qui va faire planter ton programme avec un message si jamais tu accèdes à de la mémoire à laquelle tu n'avais pas le droit d'accéder !!!!
Oh merde, je ne vois ta reponse que maintenant... et pourtant elle m'aurai bien servi...
Oui j'ai fini par avoir cette information lol, la ça marche nickel, mais j'aurai pu gagner du temps. -Werror je l'enleve generalement mais je le remet pour rendre mes projets car on est obligé. ok ça marche pour -g3, je met -g généralement et -g3 quand j'utilise fsanitize, mais je ne saurai expliquer pourquoi lol.
Merci a tous pour votre aide, je met le sujet comme résolu !!
Il vaut mieux mettre -Werror dès le début. Les débutants ne font pas de trucs rock'n'roll où il faudrait outrepasser les avertissements qui seraient des faux positifs
Dès lors tout avertissement signale un problème potentiel, qu'il est préférable de régler immédiatement. Sinon on accumule les avertissements, on ne les lit plus, et on finit par se retrouver avec un merdier ingérable (la dette technique !)
Je me permets quand même -Wno-unused, quand j'ai des pointeurs vers des fonctions qui doivent avoir le même prototype, mais dont les paramètres ne servent pas forcément.
Il vaut mieux mettre -Werror dès le début. Les débutants ne font pas de trucs rock'n'roll où il faudrait outrepasser les avertissements qui seraient des faux positifs
Dès lors tout avertissement signale un problème potentiel, qu'il est préférable de régler immédiatement. Sinon on accumule les avertissements, on ne les lit plus, et on finit par se retrouver avec un merdier ingérable (la dette technique !)
Je me permets quand même -Wno-unused, quand j'ai des pointeurs vers des fonctions qui doivent avoir le même prototype, mais dont les paramètres ne servent pas forcément.
La contre-partie d'un -Werror est de se retrouver avec des patchs à la mords-moi le nœud … genre des cast pour faire taire des warnings qu'on a du mal à comprendre, Difficile pour un débutant de concilier et -Wall -Wextra (on en rajoute des warnings) et -Werror (il faut impérativement les faire disparaître) … potentiellement n'implique pas l'existence réelle d'une erreur.
Sinon on peut déjà profiter des attributs en spécifiant le standard C2x avec gcc ou en utilisant une version récente de clang, ou si on a pas froid aux yeux, utiliser les extensions que ces compilos proposent déjà.
> genre des cast pour faire taire des warnings qu'on a du mal à comprendre
C'est justement le bon moment pour essayer de les comprendre, plutôt que de faire en sorte de ne pas les voir. A priori, je ne vois pas d'exemple de warning bénin qui ne soit pas facile à régler proprement.
Je me rappelle avoir signalé, il y a très longtemps, un bug dans la commande netdate de linux, qui aurait été évident si le programmeur avait daigné regarder les warnings. Genre le résultat d'un read affecté dans un non-signé, ce qui faisait louper la détection de problèmes ensuite (échec du read à travers le réseau, résultat négatif).
Le type devait juger que "un warning n'est pas forcément une erreur".
> et -Werror (il faut impérativement les faire disparaître) …
Absolument. Des warnings -> pas d'exécutable. Ca évite de tirer des conclusions hâtives à partir de l'exécution "pour voir" d'un source a moitié compilé de travers.
C'est une discipline de programmation. De nos jours, les ordinateurs vont vite, et on peut compiler très souvent. D'ailleurs de plus en plus les IDE passent leur temps à faire compiler les programmes pendant la frappe.
> genre des cast pour faire taire des warnings qu'on a du mal à comprendre
C'est justement le bon moment pour essayer de les comprendre, plutôt que de faire en sorte de ne pas les voir. A priori, je ne vois pas d'exemple de warning bénin qui ne soit pas facile à régler proprement.
Je me rappelle avoir signalé, il y a très longtemps, un bug dans la commande netdate de linux, qui aurait été évident si le programmeur avait daigné regarder les warnings. Genre le résultat d'un read affecté dans un non-signé, ce qui faisait louper la détection de problèmes ensuite (échec du read à travers le réseau, résultat négatif).
Le type devait juger que "un warning n'est pas forcément une erreur".
> et -Werror (il faut impérativement les faire disparaître) …
Absolument. Des warnings -> pas d'exécutable. Ca évite de tirer des conclusions hâtives à partir de l'exécution "pour voir" d'un source a moitié compilé de travers.
C'est une discipline de programmation. De nos jours, les ordinateurs vont vite, et on peut compiler très souvent. D'ailleurs de plus en plus les IDE passent leur temps à faire compiler les programmes pendant la frappe.
- Edité par michelbillaud il y a environ 1 heure
Je me demande bien pourquoi le compilateur/standard fait une différence entre un warning et un error ? Y aurait-il une raison que même un débutant pourrait être amené à comprendre ? ptêt qu'il s'agit même du fameux «un programmeur C sait ce qu'il fait, même quand il se tire dans le pied» 😄
La discipline de programmation n'a pas besoin de «tout warning est une erreur, les warnings bénins n'existent que dans le pays des merveilles et ici c'est le vrai monde réel», mais plus de «tout warning se doit d'être pris en compte». On fait du C, on est pas en train d'apprendre Ada par exemple. Il ne faut pas non plus oublier que les messages de diagnostiques se sont largement améliorés depuis quelques temps … ils en sont au stade où ils sont même clairs … pour dire 🤗
michelbillaud a écrit:
[...]
Le type devait juger que "un warning n'est pas forcément une erreur".
[...]
Bah tu juges toi-même que tous les warnings ne sont pas des erreurs puisque :
michelbillaud a écrit:
Je me permets quand même -Wno-unused, quand j'ai des pointeurs vers des fonctions qui doivent avoir le même prototype, mais dont les paramètres ne servent pas forcément.
Pourquoi ne pas classiquement faire un cast d'une expression sur (void) ?
Pourquoi ne pas simplement forcer une autre signature ?
Il y aurait des moyens de corriger cette erreur …
Quand aux programmeurs qui ne font que peu ou pas gaffe aux warnings il y en a toujours eu et il y en aura toujours, -Werror ou pas …
Pourquoi ne pas classiquement faire un cast d'une expression sur (void) ?
Je fais un peu d'embarqué (en amateur), et les options du compilo m'obligent à coller un (void) pour ignorer tous les retours de fonctions dont je ne fais rien.
Comme ça, on est sûr que je n'ai pas ignoré que la fonction retournait quelque chose. En gros, je dois m'en occuper, ou signer une décharge en mettant explicitement un (void).
Pour l'histoire des arguments non utilisés, c'est parce que la norme du langage est (pour l'instant) légèrement déficiente de ce côté-là. Mais elle se soigne. Sinon il y a l'alternative
#define UNUSED_ARG (void)
void foo(int bar, int baz) {
UNUSED_ARG baz;
...
}
Ca marche, c'est lisible, c'est maintenable, mais c'est pas standard.
Ici on est dans le contexte de programmes de débutants. A priori, les warnings des exercices sont parfaitement solubles sans faire de pirouettes, quand ils sont bénins. Et ça vaut le coup d'examiner ce qui les déclenche.
Le type de programme où j'ai le souci, c'est par exemple un "shell", avec des actions à lancer en fonction d'un mot
et qu'après avoir trouvé le mot dans la table on lance la fonction correspondante
for (....) {
if (strcmp(....)) {
commandes[i].action(argc, argv);
break;
}
}
A priori les actions ont le même prototype (un nombre, un tableau de chaines), mais dans certains cas (quit, on peut imaginer), elle n'utilise pas le tableau de chaines args (parce qu'on sait que argc == 1, et qu'on sait ce qu'il y a dans argv[0]).
Donc il n'y pas de raison de changer la signature, encore moins de la forcer. C'est juste qu'on n'utilise pas le tableau, qui a parfaitement raison d'être là quand même.
Pourquoi ne pas classiquement faire un cast d'une expression sur (void) ?
Je fais un peu d'embarqué (en amateur), et les options du compilo m'obligent à coller un (void) pour ignorer tous les retours de fonctions dont je ne fais rien.
compilos non standard …
michelbillaud a écrit:
Pour l'histoire des arguments non utilisés, c'est parce que la norme du langage est (pour l'instant) légèrement déficiente de ce côté-là. Mais elle se soigne. Sinon il y a l'alternative
#define UNUSED_ARG (void)
void foo(int bar, int baz) {
UNUSED_ARG baz;
...
}
Ca marche, c'est lisible, c'est maintenable, mais c'est pas standard.
La norme ni ne définit ni n'impose l'émission d'un quelconque warning. Les implémentations sont libres de faire ce qu'elle veulent. La construction que tu montres est standard dans le sens que c'est une expression acceptée par le standard, tu l'utilises pour faire taire un warning du compilo … et effectivement c'est lisible et maintenable.
Le problème principal de -Werror est qu'il transforme un warning (définit par l'implémentation) en erreur (qui tient au standard). Tu peux du jour au lendemain te retrouver avec un programme qui ne compile plus car après un update de ton compilo tu as de nouveaux warnings … Le comportement n'est plus reproductible ce qui produit un programme un peu plus difficile à maintenir, car tu vas le patcher de plus en plus pour faire taire les warnings …
Là, c'est pas "patcher" pour faire taire, ça serait absurde parce que contraire à l'idée du truc.
C'est patcher pour _résoudre_ le petit souci qui se pose.
Par exemple, ça coûte pas cher, en voyant
a.c:6:20: warning: comparison of integer expressions of different signedness: ‘int’ and ‘size_t’ {aka ‘long unsigned int’} [-Wsign-compare]
for (int i = 0; i < strlen(string); i++) {
^
de rectifier le type de i, qui devrait être un size_t.
Dans d'autres contextes, la valeur du size_t pourrait être trop grande pour tenir sur un int, et si on ne fait pas gaffe à comparer des choses comparables, OSEF ça va marcher, on risque de se faire pincer très fort.
Pour le -Werror, je l'enleve et le remet, c'est surtout car il me renvoi des erreurs de variables non utilisées et quand tu es en train de modifier des fonctions juste pour test deux ou trois trucs, t es obligé de modifier toutes les focntions pour que ca compile.
Je sais pas si c est claire lol, mais c est juste pour tester deux ou trois truc, un fois que j ai trouvé je le remet. De toute façon meme si tu ne le met pas, tu as quand meme les warning non ? Perso, je ne laisse jamasi des warnings, pour moi je considere ça comme une erreur, quoi qu'il arrive.
Le problème de laisser s'afficher des messages qu'on a décidé d'ignorer, c'est qu'au bout de 5 minutes on ne lit plus les messages, et qu'on ne voit pas les nouveaux qui se glissent dedans.
tout comme le problème de vouloir absolument faire disparaître des messages qui ne sont que des warnings c'est qu'au bout de 2 messages, donc même pas 5 minutes, on va faire des cast sauvages, des tournures de codes inutiles pour éviter des messages, … on rend le code illisible.
Ce ne sont pas les warnings que je remets en cause … c'est l'utilisation de -Werror. Un warning c'est un avertissement, un error c'est une erreur → deux choses bien différentes. Considérer les warnings comme des erreurs c'est un non sens. Les considérer et avec rigueur les examiner c'est normal, c'est cela qu'il faut apprendre, même aux débutants. Vouloir les enlever à tout prix parce qu'on a un -Werror pour «avoir une compilation qui passe crème» c'est du n'imp.
Le seul et unique moment où on doit avoir une absence totale de warnings (et d'erreurs évidemment) c'est lorsqu'on développe une bibliothèque. À aucun moment, l'inclusion d'un header pour utiliser ladite bibliothèque ne doit générer des messages.
Donc on s'entend bien … je te parle bien de l'utilisation de -Werror … pas de l'utilité évidente des warnings et autres messages de diagnostiques.
cast sauvage ? n'importe quel apprenant castera pour pouvoir compiler s'il a un message du genre int * expected char *found … ah ben oui … après ça compile mais ça bugue et en beauté … et on a droit à des messages du genre «je comprends pas, ça compile mais ça plante»
tournures de code inutiles ? mmm je ne sais pas moi … par exemple :
michelbillaud a écrit:
#define UNUSED_ARG (void)
void foo(int bar, int baz) {
UNUSED_ARG baz;
...
}
et encore c'est la «moins pire des solutions». Parce qu'il y a une forme de lisibilité, enfin jusqu'au jour où tu trouves un bug car le paramètre n'est pas utilisé mais tu n'as pas de warnings parce que tu l'auras fait taire pour simplement pouvoir compiler …
Le compilateur ne vérifie pas moins de choses. Et c'est là un argument supplémentaire contre l'utilisation du -Werror, au moins dans un contexte de déploiement. En effet les compilateurs diagnostiquent de mieux en mieux. Chaque nouvelle version vient avec un lot supplémentaire de diagnostiques. Utilise un -Werror et un simplement changement de version de ton compilo fout en l'air tes tests automatiques, tes builds automatiques, etc … et tout ça pour un warning qui n'était pas diagnostiqué avec gcc 9 mais l'est avec gcc 10 ?
Je ne dis pas qu'il ne faut pas le vérifier, je dis que ça ne doit en aucun cas être bloquant.
Et oui, c'est là où la philosophie du C (le programmeur sait ce qu'il fait) intervient. Si tu veux une compilation qui passe sans aucun message pour avoir un exécutable alors ne fait pas du C, fait de l'Ada ou du Rust (et encore … rust ça va).
L'esprit du C :
Trust the programmer.
Don't prevent the programmer from doing what needs to be done.
Keep the language small and simple.
Provide only one way to do an operation.
Make it fast, even if it is not guaranteed to be portable.
Make support for safety and security demonstrable.
Et on peut d'autant plus croire le dèv qu'on possède un compilo qui diagnostique bien, et un -Werror c'est juste empêcher le dèv de faire ce qu'il faut (parfois) …
Dans ton cast sauvage, c'est une erreur qui ne se corrige ni par un cast, ni par une absence de cast. Les avertissement signalent un probleme potentiel, mettre WError oblige à se pencher dessus. Mais bien sûr ils n'empecheront personne d'être stupide. Je ne vois pas où est l'argument.
Le cas des parametres non utilisés devrait etre réglé bientôt par un attribut (prochain standard ?)
Et tes systèmes de build automatique, c'est très bien, mais là on parle de l'enseignement aux débutants. Il faut qu'ils lisent, comprennent et rectifient.
Les points que tu cites comme étant "l'esprit du C " etaient un article de foi du premier standard "le programmeur infaillible sait ce qu'il fait LOL", le comité de normalisation est un peu revenu sur terre ensuite.
Si le compilateur version N détecte mieux un lézard que la version N-1, il faudrait s'en priver ?
× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
× Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
Le Tout est souvent plus grand que la somme de ses parties.
On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent
Le Tout est souvent plus grand que la somme de ses parties.
Le Tout est souvent plus grand que la somme de ses parties.