vérifier NULL avant d’appeler gratuitement

De nombreux appels de pointeurs libérant du code C:

if (p) free(p); 

Mais pourquoi? Je pensais que C standard dit que la fonction free ne fait rien avec un pointeur NULL. Alors pourquoi une autre vérification explicite?

La construction:

 free(NULL); 

a toujours été OK en C, retour au compilateur UNIX original écrit par Dennis Ritchie. Avant la normalisation, il se peut que certains compilateurs médiocres ne l’aient pas correctement utilisé, mais de nos jours, tout compilateur qui ne peut pas légitimement s’appeler légitimement compilateur du langage C. Son utilisation conduit généralement à un code plus clair et plus facile à gérer.

Si je comprends bien, le non-op sur NULL n’était pas toujours là.

Dans le mauvais vieux temps de C (vers 1986, sur un compilateur cc standard pré-ANSI), free (NULL) viderait le kernel. La plupart des développeurs ont donc testé NULL / 0 avant d’appeler gratuitement.

Le monde a parcouru un long chemin et il semble que nous n’avons plus besoin de faire le test. Mais les vieilles habitudes ont la vie dure;)

http://discuss.joelonsoftware.com/default.asp?design.4.194233.15

J’ai tendance à écrire ” if (p) free(p) ” beaucoup, même si je sais que ce n’est pas nécessaire.

Je me blâme en partie moi-même parce que j’ai appris le bon vieux temps où free(NULL) segfault et je me sens toujours mal à l’aise de ne pas le faire.

Mais je reproche également à la norme C de ne pas être cohérente. Par exemple, si fclose (NULL) est bien défini, je n’éprouverais aucun problème d’écriture:

 free(p); fclose(f); 

Ce qui arrive souvent quand on nettoie des choses. Malheureusement, il me semble étrange d’écrire

 free(p); if (f) fclose(f); 

et je me retrouve avec

 if (p) free(p); if (f) fclose(f); 

Je sais, ce n’est pas une raison rationnelle mais c’est mon cas 🙂

Les compilateurs, même lorsque l’inline n’est pas assez intelligent pour savoir que la fonction reviendra immédiatement. Mettre en place des parameters, etc. sur la stack et configurer l’appel est évidemment plus coûteux que de tester un pointeur. Je pense que c’est toujours une bonne pratique d’éviter l’exécution de quoi que ce soit, même lorsque rien n’est impossible. Tester pour null est une bonne pratique. Une pratique encore meilleure consiste à vous assurer que votre code n’atteint pas cet état et par conséquent, élimine la nécessité du test.

il peut y avoir une implémentation personnalisée de free () dans un environnement mobile. Dans ce cas, free (0) peut causer un problème. (ouais, mauvaise implémentation)

Il y a deux raisons distinctes pour lesquelles une variable de pointeur peut être NULL:

  1. parce que la variable est utilisée pour ce qu’on appelle un type d’option dans la théorie des types et qu’elle contient soit un pointeur sur un object, soit NULL pour ne rien représenter,

  2. car il pointe vers un tableau et peut donc être NULL si sa longueur est égale à zéro (comme malloc(0) est autorisé à renvoyer NULL, défini par l’implémentation).

Bien qu’il ne s’agisse que d’une distinction logique (en C, il n’y a pas de types d’options ni de pointeurs spéciaux sur les tableaux et nous n’utilisons que des pointeurs pour tout), il convient de toujours préciser comment une variable est utilisée.

Le fait que la norme C exige que free(NULL) ne fasse rien est la contrepartie nécessaire du fait qu’un appel réussi à malloc(0) peut renvoyer NULL . Ce n’est pas une commodité générale, c’est pourquoi par exemple, fclose() nécessite un argument non-NULL. Abuser de l’autorisation d’appeler free(NULL) en transmettant une valeur NULL qui ne représente pas un tableau de longueur nulle donne l’impression d’être bidon et erroné.

Si vous comptez sur free (0), c’est OK, et il est normal que votre pointeur soit null à ce stade, veuillez le préciser dans le commentaire // may be NULL

Cela peut être simplement du code explicite, en disant oui je sais, j’utilise aussi p comme drapeau .

 if (p) free(p); 

pourquoi une autre vérification explicite?

Si j’écris quelque chose comme ça, c’est pour transmettre la connaissance spécifique que le pointeur peut être NULL … pour aider à la lisibilité et à la compréhension du code. Parce que ça fait un peu bizarre de dire ça:

 assert(p || !p); free(p); 

(Au-delà de leur apparence étrange, les compilateurs sont connus pour se plaindre de “condition toujours vraie” si vous augmentez vos avertissements dans de nombreux cas.)

Donc, je le vois comme une bonne pratique, si ce n’est pas clair du contexte.

Le cas contraire, où un pointeur devrait être non nul, est généralement évident à partir des lignes de code précédentes:

 ... Unhinge_Widgets(p->widgets); free(p); // why `assert(p)`...you just dereferenced it! ... 

Mais si ce n’est pas évident, avoir l’assertion peut valoir les caractères tapés.