164 votes

En C, pourquoi certaines personnes jettent le pointeur avant de le libérer?

Je suis en train de travailler sur une ancienne base de code et à peu près chaque appel de free() utilise un plâtre sur son argument. Par exemple,

free((float *)velocity);
free((float *)acceleration);
free((char *)label);

où chaque pointeur est du correspondant (et de la correspondance) de type. Je ne vois pas l'intérêt de faire cela. C'est très vieux code, donc je me demandais si c'est un K&R chose. Si oui, en fait, je souhaite soutenir l'ancienne compilateurs qui auraient eu besoin de cela, alors je ne veux pas les supprimer.

Est-il une raison technique à utiliser ces distributions? Je n'ai pas encore vu beaucoup de raison pragmatique à les utiliser. Quel est le point de nous rappeler le type de données à droite avant de la libérer?

EDIT: Cette question n'est pas un doublon de l'autre question. L'autre question est un cas particulier de cette question, qui je pense est évident si l'fermez les électeurs de lire toutes les réponses.

Colophon: je suis en train de donner le "const réponse" le coche parce que c'est une bonne foi vraie raison pour laquelle cette opération peut être effectuée; toutefois, la réponse à ce sujet étant un pré-ANSI C personnalisé (au moins chez certains programmeurs) semble être la raison pour laquelle il a été utilisé dans mon cas. Beaucoup de bons points par beaucoup de gens ici. Je vous remercie pour vos contributions.

169voto

Manos Nikolaidis Points 7375

Casting peut être nécessaire pour résoudre les avertissements du compilateur si les pointeurs sont const . Voici un exemple de code qui provoque un avertissement sans lancer l'argument de free:

 const float* velocity = malloc(2*sizeof(float));
free(velocity);
 

Et le compilateur (gcc 4.8.3) dit:

 main.c: In function ‘main':
main.c:9:5: warning: passing argument 1 of ‘free' discards ‘const' qualifier from pointer target type [enabled by default]
     free(velocity);
     ^
In file included from main.c:2:0:
/usr/include/stdlib.h:482:13: note: expected ‘void *' but argument is of type ‘const float *'
 extern void free (void *__ptr) __THROW;
 

Si vous utilisez free((float*) velocity); le compilateur arrête de se plaindre.

60voto

Lundin Points 21616

La pré-norme C a n void* mais seulement char*, de sorte que vous devait jeter tous les paramètres passés. Si vous rencontrez ancien code en C, vous pouvez donc trouver de telles distributions.

Même question avec les références.

Lorsque le premier C de norme a été publiée, les prototypes de malloc et free changé de disposer char* de la void* qu'ils ont encore aujourd'hui.

Et bien sûr dans la norme C, ces distributions sont superflus et seulement nuire à la lisibilité.

33voto

egur Points 4779

Voici un exemple où free échouerait sans un casting:

 volatile int* p = (volatile int*)malloc(5 * sizeof(int));
free(p);        // fail: warning C4090: 'function' : different 'volatile' qualifiers
free((int*)p);  // success :)
free((void*)p); // success :)
 

En C, vous pouvez obtenir un avertissement (en avoir un dans VS2012). En C ++, vous obtiendrez une erreur.

De rares cas mis à part, le casting vient gonfler le code ...

Edit: j'ai casté à void* not int* pour démo l'échec. Il fonctionnera de la même manière que int* sera converti en void* implicitement. Ajout du int* code.

30voto

chux Points 13185

Vieux raisons: 1. En utilisant free((sometype*) ptr), le code est explicite sur le type du pointeur doit être considérée comme faisant partie de l' free() appel. Le cast explicite est utile lors de l' free() est remplacé par un (do-it-yourself) DIY_free().

#define free(ptr) DIY_free(ptr, sizeof (*ptr))

Un DIY_free() était (est) un moyen, surtout en mode de débogage, de faire une analyse de l'exécution du pointeur d'être libéré. C'est souvent jumelé avec un DIY_malloc() ajouter sententials, mondial de l'utilisation de la mémoire d'un dénombrement, etc. Mon groupe a utilisé cette technique depuis des années avant que d'outils plus modernes apparaissent. Il obligé que l'élément libre avait été moulé pour le type a été initialement attribuée.

  1. Étant donné les nombreuses heures passées à traquer des problèmes de mémoire, etc, des petits trucs, comme le casting du type libre avais, pour aider à la recherche et de la réduction du débogage.

Moderne: en Évitant const et volatile mises en garde adressées par Manos Nikolaidis@ et @egur. Pensé que je pourrais noter les effets de la 3 qualificatifs: const, volatile, et restrict.

[edit] Ajout de l' char * restrict *rp2 par @R.. commentaire

void free_test(const char *cp, volatile char *vp, char * restrict rp, 
    char * restrict *rp2) {
  free(cp);  // warning
  free(vp);  // warning
  free(rp);  // OK
  free(rp2);  // warning
}

int main(void) {
  free_test(0,0,0,0);
  return 0;
}

16voto

Zack Points 44583

Voici une autre hypothèse alternative.

On nous dit que le programme a été écrit pré-C89, ce qui signifie qu'il ne peut pas être travail autour de quelques-uns sorte de décalage avec le prototype de l' free, parce que non seulement il n'y avait pas une telle chose comme const ni void * avant C89, il n'y a pas une telle chose comme un prototype de fonction avant C89. stdlib.h lui-même est une invention de la commission. Si le système d'en-têtes de la peine de déclarer free , ils auraient fait comme ceci:

extern free();  /* no `void` return type either! */

Maintenant, le point clé ici est que l'absence de prototypes de fonction signifiait que le compilateur n'a aucun argument de la vérification de type. Il a appliqué l'argument par défaut promotions (les mêmes que celles qui s'appliquent toujours à variadic les appels de fonction) et qu'il a été. La responsabilité de prendre les arguments à chaque callsite ligne avec le destinataire de l'appel attentes de jeter entièrement par le programmeur.

Toutefois, cela ne signifie pas encore qu'il était nécessaire de lancer l'argument free sur la plupart des K&R compilateurs. Une fonction comme

free_stuff(a, b, c)
    float *a;
    char *b;
    int *c;
{
    free(a);
    free(b);
    free(c);
}

doit avoir été compilé correctement. Donc, je pense que ce que nous avons ici est un programme écrit pour faire face à un buggy compilateur pour un environnement hors du commun: par exemple, un milieu où l' sizeof(float *) > sizeof(int) et le compilateur ne pas utiliser la convention d'appel appropriée pour les pointeurs, à moins que vous les jeter au moment de l'appel.

Je ne suis pas au courant d'un tel environnement, mais cela ne signifie pas qu'il n'y avait pas un seul. Les plus probables candidats qui viennent à l'esprit sont coupe-bas "petit C" compilateurs pour des 8 et 16 bits micros dans le début des années 1980. Aussi je ne serais pas surpris d'apprendre que les premiers Crays eu des problèmes de ce genre.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X