Pourquoi convertir la valeur de retour de free en null?

82

Je lis un livre ( Programmation avec des fils POSIX de Butenhof, 1997) qui utilise C, et je suis tombé sur la ligne suivante:

(void)free(data);

Ici, dataest juste un pointeur vers une structure allouée,

data = malloc(sizeof(my_struct_t));

Pourquoi le résultat freeest-il lancé void?

D'après ma compréhension de C, cela ne semble pas logique pour deux raisons:

  • La fonction gratuite revient déjà void
  • Le code n'utilise pas la valeur de retour (il n'est même pas affecté à une variable)

Le livre a été écrit en 1997. Est-ce une sorte d'héritage?

L'auteur mentionne que les exemples ont été exécutés sur Digital Unix 4.0d, mais je ne peux toujours pas imaginer une raison de lancer le résultat d'une fonction si vous n'utilisez pas ce résultat.

Adam Johnston
la source
Quelques explications possibles peuvent être trouvées ici: stackoverflow.com/questions/689677/…
Timbo
3
Par curiosité, quelle est la date de publication de votre livre C? (De quel livre s'agit-il?) Si c'est avant 1995 environ, cela pourrait être justifié - les compilateurs C standard n'étaient pas omniprésents avant cette date. S'il est publié après cela et contient toujours le casting (et aucune explication pourquoi), préoccupez-vous des autres mauvaises habitudes qu'il vous enseigne. Obtenez un livre plus récent!
Jonathan Leffler
10
Ressemble à la programmation avec les threads POSIX
Eugene Sh.
3
@JonathanLeffler, comme mentionné dans mon article d'origine, le livre a été publié en 1997 et utilisait UNIX 4.0d. Le livre est "Programmation avec des fils POSIX" par David R. Butenhof. Jusqu'à présent, il a été très informatif et est écrit par l'un des contributeurs d'origine à la norme des threads POSIX.
Adam Johnston
6
J'ai utilisé ma copie de cela la semaine dernière - oui, c'est toujours utile. Il a été écrit à l'aube du «standard C omniprésent» (j'ai dit «vers 1995»). 'UNIX 4.0d' ressemble à Digital UNIX - c'est là que Butenhof a travaillé, et la préface le mentionne. Traitez l'acteur free()comme une bizarrerie dans le livre que vous n'avez pas besoin d'émuler. Il y a longtemps, il était semi-pertinent, mais il n'est plus pertinent.
Jonathan Leffler

Réponses:

100

Si nous parlons de la freefonction standard , son prototype est

void free(void *ptr);

Par conséquent, le casting est complètement inutile.
Maintenant, quelques spéculations.

L'auteur a peut-être oublié d'inclure l'en- stdlib.htête déclarant ce prototype, donc le compilateur en assume le type de retour comme int. Maintenant, lors de l'analyse statique de ce code, le compilateur avertissait de la valeur de retour inutilisée de ce qu'il pense être une non- voidfonction. De tels avertissements sont généralement réduits au silence en ajoutant le casting à void.

Eugene Sh.
la source
50
Mais notez que si le casting a été introduit pour la raison spéculée, alors l'utiliser pour faire taire l'avertissement est incorrect . Dans ce cas, le compilateur attribuera un type différent de freecelui qu'il a réellement, avec pour résultat que l'appel a un comportement non défini (en supposant la sémantique C90, où l'appel d'une fonction non déclarée ne présente pas intrinsèquement UB dans tous les cas). En pratique, il est plausible que cela se traduise par une mauvaise conduite de bonne foi sur certains systèmes. La bonne solution consiste à fournir une déclaration correcte pour la fonction.
John Bollinger
11
En particulier, les exemples de "Programmation avec des threads POSIX" n'incluent pas à plusieurs reprises les en-têtes standard appropriés. Peut-être que c'était une mauvaise pratique de l'auteur, ils auraient pu utiliser une configuration de compilateur non standard qui incluait toutes les bibliothèques standard par défaut.
Lundin
74

Ce serait un héritage!

Avant qu'il n'y ait un standard C, la free()fonction aurait été (implicitement) de type int- car il n'y avait pas encore de type fiablevoid pour qu'elle revienne. Aucune valeur n'a été renvoyée.

Lorsque le code a été modifié pour la première fois pour fonctionner avec des compilateurs C standard, il ne comprenait probablement pas <stdlib.h>(car il n'existait pas avant la norme). L'ancien code écrivait extern char *malloc();(peut-être sans extern) pour les fonctions d'allocation (de même pour calloc()et realloc()), et n'avait pas besoin de déclarer free(). Et le code convertirait ensuite la valeur de retour dans le type correct - car cela était nécessaire sur au moins certains systèmes (y compris celui sur lequel j'ai appris C).

Quelque temps plus tard, la (void)distribution a été ajoutée pour indiquer au compilateur (ou, plus probablement, lint) que "la valeur de retour de free()est délibérément ignorée" pour éviter une plainte. Mais il aurait été préférable d'ajouter <stdlib.h>et de laisser sa déclaration extern void free(void *vp);dire lintau compilateur qu'il n'y avait aucune valeur à ignorer.

JFTR: au milieu des années 80, l'ICL Perq était à l'origine sur une architecture orientée mots et l' char *adresse d'un emplacement mémoire était un nombre très différent du pointeur "else_else" vers le même emplacement. Il était crucial de déclarer en char *malloc()quelque sorte; il était crucial d'en convertir le résultat en n'importe quel autre type de pointeur. Le casting a en fait changé le nombre utilisé par le CPU. (Il y avait aussi beaucoup de joie lorsque la mémoire principale de nos systèmes a été mise à niveau de 1 Mio à 2 Mio - puisque le noyau utilisait environ 3/4 Mio, cela signifiait que les programmes utilisateur pouvaient utiliser 1 1/4 Mio avant la pagination, etc.)

Jonathan Leffler
la source
9
Je viens d'ouvrir une copie de K&R, 1ère édition, qui contient une implémentation de free()sur p. 177 qui revient implicitement int.
ex nihilo
9
Bien sûr - a voidété ajouté à certains systèmes (Unix System III, peut-être) avant la publication de la norme, mais cela ne faisait pas partie de C lorsque K&R 1st Edn a été écrit (1978). Une fonction qui n'a pas retourné de valeur a été déclarée sans type de retour (ce qui signifie qu'elle a renvoyé int), et tant que vous n'avez pas utilisé la valeur qui n'a pas été retournée, il n'y a pas eu de problème. La norme C90 devait traiter ce type de code comme valide - elle aurait échoué lamentablement comme une norme ne l'avait pas fait. Mais C99 a supprimé les intrègles «implicite » et «déclaration de fonction implicite». Tout le code du monde n'a pas été rattrapé.
Jonathan Leffler
5
Op affirme que le livre a été écrit en 1997. Ce dont vous parlez ici est très tôt le "K&R C" pré-standard et il semble peu probable que quelqu'un écrive un livre à ce sujet. Le seul livre de ce genre qui existait à ma connaissance était en effet K&R 1ère édition.
Lundin
C'était une pratique fréquente (si ironique) de ne pas inclure d'en-têtes si vous pensiez que vous pouviez vous en sortir avec une déclaration implicite, car les gens pensaient que cela réduirait les temps de construction.
Spencer
Quelqu'un utilise-t-il un (void)casting pour printf()??
Luis Colorado
11

Ce casting n'est pas nécessaire. Cela n'aurait probablement pas été le cas à l'époque, car C avait été normalisé sous la forme de C89.

Si cela avait été le cas, cela serait dû à une déclaration implicite . Cela signifiait généralement que la personne qui écrivait le code avait oublié #include <stdlib.h>et qu'un analyseur statique était utilisé. Ce n'est pas la meilleure solution de contournement et une bien meilleure idée aurait été de le faire à la #include <stdlib.h>place. Voici quelques mots de C89 sur la déclaration implicite:

Si l'expression qui précède la liste d'arguments entre parenthèses dans un appel de fonction consiste uniquement en un identifiant, et si aucune déclaration n'est visible pour cet identifiant, l'identifiant est déclaré implicitement exactement comme si, dans le bloc le plus à l'intérieur contenant l'appel de fonction, la déclaration

extern int identifier();

apparu.

Mais c'est étrange car ils ne convertissent pas le résultat de l' mallocun et de l' autre mallocet freesont dans le même fichier d'en-tête.

Il est également possible que ce soit juste une erreur ou un moyen de dire au lecteur qu'il freene renvoie aucun résultat.

SS Anne
la source
5
Ce n'est pas parce qu'un langage est standardisé que tout le monde met à jour instantanément sa chaîne d'outils et son code pour s'y conformer. Il est plausible que le "K&R" C à l'ancienne soit resté environ 8 ans. Pourtant, je conviens qu'il est étrange qu'un outil d'analyse statique nécessite un cast pour freemais pas pour malloc.
dan04
4
@ dan04 Vous utilisez généralement le résultat de malloc;) Je ne suis pas fan d'écrire des choses comme (void) printf (...) pour arrêter le compilateur de cracher des avertissements mais "doit compiler sans aucun avertissement, même les plus stupides" est quelque chose qui arrive dans beaucoup de projets.
richardb