11
votes

calloc - utilité de la mise à zéro de la mémoire

Quel est l'avantage de la mise à zéro de la mémoire (i.e. calloc () sur malloc () )? Ne changez-vous pas la valeur à quelque chose d'autre de toute façon?


0 commentaires

7 Réponses :


1
votes

Il est bon de savoir que tout ce que vous allociez est initialisé à zéro. De nombreux bugs sont venus du code qui utilise une mémoire non initialisée. De plus, certaines valeurs par défaut dans les structures / classes pourraient être correctes comme zéro afin que vous n'ayez pas besoin de changer toutes les valeurs après le malloc.

Par exemple, allouer une structure qui a des pointeurs dedans avec Malloc. Les chèques nuls ne vont pas toujours travailler à moins qu'ils ne soient placés sur NULL. Si vous appelez, vous n'avez pas à faire les étapes d'initialisation supplémentaires pour les valeurs du pointeur.


1 commentaires

Comme je l'ai dit dans un autre commentaire: calloc pour définir des pointeurs définis sur null est inutile car il n'est pas garanti par la norme que tous les bits-zéro == null < / code>.



3
votes

Supposons que vous souhaitez rédiger une implémentation de tri de comptage ou une approche d'abord de la recherche d'un graphique et gardez une trace des sommets visités. Vous mettez à jour votre mémoire lorsque l'algorithme fonctionne (plutôt que d'attribuer une valeur juste une fois). Vous devez l'initialiser à zéro au début. Si vous n'aviez pas calloc , vous devez le passer manuellement et l'initialiser à zéro au début de votre algorithme. calloc peut potentiellement le faire plus efficacement pour vous.


3 commentaires

Évoquage parce que le reste des réponses ne mentionnent que les avantages de la recherche de bogues ou des avantages à court terme (qui sont superbes, aussi). Ils ne mentionnent pas (ce qui est probablement) l'objectif initial de CalloC. Parfois, vous avez un algorithme qui alloue la mémoire et nécessite que les données soient initialisées à zéro. Aussi simple que cela. Juste parce que vous serez finalement stocké une valeur différente ne signifie pas que zéro n'est pas la valeur initiale correcte.


@Merlyn: Pour une certaine valeur de "le reste des réponses" :-)


Oh pardon. Je n'ai pas réalisé que tu parlais toujours! ;)



8
votes
  1. En sachant quelle valeur est déjà là, un programmeur peut prendre des raccourcis et faire certaines optimisations. Plus fréquemment, calloc une structure avec des pointeurs: ils sont initialisés à NULL.
  2. Et si le programmeur a oublié d'initialiser quelque chose dans l'allocation? Au lieu de choses aléatoires, zéro est une grande valeur par défaut.

    Dans un système de contrôle de processus en temps réel J'ai travaillé il y a longtemps, nous nous sommes installés sur la logique de mise sous tension initialise la totalité de la RAM à 0xcc, l'instruction INTERRUPT 3 . Cela provoquerait que le processeur pénètre dans le moniteur (un débogueur primitif) si elle exécutait en quelque sorte une mémoire ininitialisée. (Inféru, la mémoire 8086 exécute la mémoire contenant des zéros car ils sont ajout [bx + si], al . Même 32 bits les entraîne d'être Ajouter [AX], AL instructions.)

    Je ne me souviens pas si nous avons déjà trouvé un programme fuguelle, mais les valeurs correspondant à 0xcc dans diverses valeurs: 52 428 (non signé 16 bits), -19 660 (signé de 16 bits), -107374176 (flotteur 32 bits), et -9.25596313493e + 61 (flotteur 64 bits) ont sauté dans beaucoup d'endroits inattendus. En outre, certains caractères du code s'attendant à être 7 bits ASCII - c'est-à-dire un bogue - nous a alerté à sa présence lorsqu'il a essayé de traiter 0xcc.


11 commentaires

CalloC Pour définir les pointeurs définis sur NULL est inutile car il n'est pas garanti par la norme que toutes les bits-zéro == null . De même pour les points flottants.


Cela n'a pas été vrai depuis la fin des années 1970. Toutes les architectures importantes utilisent (vide *) 0 comme null, et les formats de points flottants IEEE utilisent tous "tous les bits zéro" comme vrai zéro.


(void *) 0 n'est pas nécessairement tous les bits-zéro. Le compilateur doit faire la traduction de (void *) 0 à la "constante de pointeur null" appropriée. De même, lorsque vous écrivez p = 0; et p est un pointeur, le compilateur doit définir p sur un motif bit qui est égal à la NULL POINTER Constante, qui peut ne pas être tous des bits zéro.


De même titre entier (autre que sans signé Char et les types de taille fixe C99 (U) inn_t), sont autorisés à avoir des bits de rembourrage, le réglage à 0 peut être une représentation de piège (pour une extrême extrême Exemple S'il y a un peu de parité inverse, alors tous les bits-zéro sont une violation de la parité). Peu probable, carrément mal, mais si vous vivez par la norme, vous pouvez mourir par la norme ...


Quelqu'un a-t-il de vrais exemples d'architectures qui n'utilisent pas tous les bits zéro comme null?


@Alok, a obtenu des exemples modernes de la NULL non nul? Pour référence, voici les dates que j'ai proposées pour Thos dans cette liste: Honeywell-Bull = Début 1990; Prime-50 = 1970; Eclipse MV = années 1980; CDC Cyber ​​180 = 1984; Vieux HP 3000 = 1970; Symbolique Lisp Machine = 1980s; "Quelques" machines à craoure 64 bits ... L'ère est inconnue, mais probablement des modèles précoces donc des années 1980, au début des années 90; 8086 - Celui-ci est inexact dans sa mention. Le mode 16 bit était "Segment: Décalage" de la taille de 16bits, le décalage a toujours commencé à 0 et était analogue à un pointeur.


@Alok: Prime est à peine un exemple architectural moderne, et les généraux de données étaient obsolètes dans les années 1980. Je serais surpris s'il y avait un vrai compilateur C pour eux. En fait, tous les exemples cités sont rarement vus (crayons) ou obsolètes.


@Wallyk et @jason: Le fait est qu'il y a eu des architectures avec des pointeurs NULL-BITS-ZERO-ZERO-ZERO. Nous ne savons pas s'il n'y en aurai plus dans le futur, cependant. Fondamentalement, je trouve facile d'écrire du code sans l'hypothèse, donc je le fais: vous avez donc raison que l'hypothèse est valable pour les ordinateurs actuels, mais que cela n'est pas garanti par la norme, et puisque je peux facilement obtenir facilement le même effet. Facilement, je ne ressens jamais la nécessité de compter sur tous les bits-zéro == 0 pour les pointeurs ou pour les valeurs à virgule flottante.


Il est obsolète ou non, j'ai vu une éclipse générale de données en bourdonnement dans un centre de données moderne que récemment - vraisemblablement relève fidèlement de quelque chose d'une certaine importance. Cela a eu l'air un peu hors de propos.


Intéressant de voir quelles sont les différentes personnes de "vieux" de "vieux". Vous pourriez avoir une opinion différente des ordinateurs du début des années 90 si vous programmez au début des années 90, que si votre idée d'obsolète Tech est Pentium D ;-)


La représentation binaire de NULL ne dépend pas de l'architecture (AFAIK), mais est le choix du fournisseur du compilateur. L'ancien compilateur Watcom C que j'ai utilisé dans le passé (sur X86) représentait un pointeur NULL avec 0xFFFFFFFF.



0
votes

En plus des avantages des variables d'initialisation, CalloC, aident également à suivre les bugs.

Si vous utilisez accidentellement un bit de la mémoire allouée sans l'initialisation correctement, l'application échouera toujours de la même manière. Par exemple, avec une violation d'accès d'un pointeur NULL. Avec MALLOC, la mémoire a des valeurs aléatoires et cela peut entraîner l'échec du programme de manière aléatoire.

Les défaillances aléatoires sont très difficiles à traquer et que CalloC aide à éviter ceux-ci.


0 commentaires

18
votes

Il y a deux camps: on dit que l'initialisation des variables lorsqu'elles sont déclarées, aident à trouver des bugs. Les personnes de ce camp assurent que tout ce qu'ils déclarent être initialisés. Ils initialisent les pointeurs à null , int s à 0, etc. L'idée est que tout est déterminé et quand ils voient un null -Poinger Dans un débogueur, ils savent immédiatement que cela n'a pas été fixé correctement. Il peut également aider votre programme à se bloquer pendant les tests en raison de NULL -Poinger latérorcoration plutôt que de crash mystérieusement en production.

L'autre camp dit que l'initialisation des variables à la déclaration rend les choses plus difficiles à déboguer, car un compilateur ne peut désormais vous avertir des variables "utilisées sans être définie".

sans vous dire ma préférence personnelle 1 : Si vous appartenez au premier camp, vous voudriez calloc () au lieu de MALLOC () . Si vous appartenez au deuxième camp (qui apparemment vous faire), vous préférez masloc () sur calloc () . .

Maintenant, il y a deux exceptions:

  • Si vous appartenez au camp "Initialiser tout" ", vous ne CALLOC () Mais MALLOC () Parce que vous initialisez les numéros de point flottant ou les pointeurs, Et vous savez que tous les bits zéro ne signifie pas nécessairement 0 pour eux. Ou, vous ne voulez pas les frais généraux supplémentaires.
  • Si vous appartenez à la "définie lorsque vous devez" camper, vous pouvez utiliser calloc () lorsque vous allouez des données et que vous voulez que ce soit tous les zéros. Par exemple, si vous souhaitez calculer la somme de la ligne d'un N par m alloué dynamiquement int données.

    1 Vous pouvez voir mes réponses à de nombreuses questions ici pour voir quel camp j'appartiens: -).


11 commentaires

J'aimerais que vous nommiez qu'un ordinateur a fait de ce côté de 1970 qui n'utilise pas les zéros pour les pointeurs NULL ou les valeurs de points flottants à zéro. Sans parler, les dernières années, j'ai programmé Windows et Linux, un malloc simple fait zéro de la mémoire. Je crois que c'est censé être une fonctionnalité de sécurité.


Tous les formats Point flottant IEEE définissent le cas particulier de «tous les bits zéro» représente le vrai zéro.


C'est plus une question de ce qui est garanti par la norme. Si je veux vraiment null des pointeurs, je les définirai sur null dans une boucle.


@akillio: C'est presque une question philosophique, cependant: Programmez-vous à la norme ou programmez-vous les implémentations que vous connaissez? Personnellement, j'essaie de programmer à la norme si Je vous écris au code supposé-portable: il est plus facile que d'apprendre à propos de chaque ordinateur de ce côté de 1970. J'ai été véritablement surpris par les compilateurs faisant Quelque chose que je pensais "n'arrive jamais". Un exemple qui ressort à l'esprit est un ABI ABI avec des types de données MiddleDian, FFS. Évidemment, 0 était toujours bodue 0, donc pas l'exemple que vous avez demandé.


En outre, je me souviens vaguement que sur Linux au moins, MALLOC ne efface que la mémoire le premier la main des mains qui bloquent le code de niveau utilisateur dans le processus. Si une allocation est libérée puis attribuée à nouveau, tout dans le même processus, il pourrait être non nul. Mais je ne me souviens pas pourquoi je pense que ça. Si j'ai raison, cela va simplement montrer que vous ne devriez pas compter sur le comportement "bien connu" mais non spécifié, et si je me trompe, cela va montrer que i ne devrait pas compter sur le comportement "bien connu" que je ne trouve aucune documentation à soutenir, car ma mémoire est mangée ;-)


@Steve: the BRK () ou sbrk () appels système (l'appel du système Linux pour développer l'allocation de mémoire) renvoie la mémoire à zéro pour des raisons de sécurité. Le gestionnaire de tas demande une mémoire supplémentaire de SBRK (). Mais quand une allocation locale libère quelque chose, le gestionnaire de tas ne le dégage probablement pas avant qu'une allocation ultérieure ne définit que les informations d'en-tête pour la gérer.


"Vous initialisez les chiffres de points flottants ou les pointeurs". Ou int (voir mon commentaire sur la réponse de Wallyk). Je dis si vous allez être pédants, soyez vraiment pédantique.


UPVOTE pour présenter objectivement une controverse intéressante et pertinente :)


@Steve Jessop: Avez-vous un pointeur à des informations sur les types de données «Middle-Endian»? Cela semble terrible et intéressant (bien au moins un peu) en même temps.


@Michael: Catb.org/jargon/html/m/middle-endian.html - mais il a très peu d'informations.


J'aime beaucoup les commentaires sur cette question (ma réponse et la réponse de Wallyk). Merci tout le monde!



0
votes

Tout d'abord, vous ne pouvez pas terminer des pointeurs, du moins pas si vous souhaitez suivre la norme C.

Deuxièmement, les bugs deviennent simplement masqués lorsque vous encombrez le membre avec tous les zéros. C'est une bien meilleure pratique d'avoir une version de débogage de Malloc qui initialise la mémoire à quelque chose qui se bloque toujours, telle que 0xCDCDCDCD.

Ensuite, lorsque vous voyez une touche d'accès, vous connaissez le problème tout de suite. Il est également bénéfique d'avoir une fonction gratuite de débogage qui fouettera la mémoire thje avec un motif différent de sorte que ceux qui touchent la mémoire après sa libération, obtenez une surprise inattendue.

Travailler sur un système intégré, callocing juste pour "être sûr", n'est généralement pas une option. Vous allouez généralement et peupler en une fois de sorte que Calloc juste pour hommes, vous êtes double de mémoire.


0 commentaires

0
votes

Personne n'a touché l'aspect de la performance, je suppose que je devrais devoir. Si vous devez écrire un programme très rapide, Malloc avec un Memset intégré «juste au cas» n'est pas un bon moyen d'y aller. Peu importe la rapidité du memset, ce sera toujours trop lent. Parfois, vous devez initialiser un vecteur ou un tableau afin que le vrai problème ait le contrôle de vos cycles d'horloge (je ne les gaspillant pas). J'ai entendu une citation une fois "vous ne devriez jamais abandonner les performances accidentellement", ce qui signifie que, d'un point de vue de la performance, vous devez toujours savoir pourquoi vous avez choisi de mettre en œuvre le code d'une manière ou d'une autre (ce que les avantages et les avantages sont et comment ils sont pesés contre mutuellement dans le cas spécifique).

Si vous avez un tampon qui sera rempli d'une chaîne, il pourrait être "agréable d'avoir" pour l'initialiser avant que la chaîne soit remplie, mais la plupart conviendront que c'est un gaspillage complet de cycles d'horloge. Si vous écrivez une nouvelle fonction STRO *, vous voudrez peut-être - à des fins de débogage - Remplissez le tampon avec une valeur qui ne devrait généralement pas apparaître, mais cela aura été supprimé du temps de distribution.

Comme d'autres personnes ont mentionné, le compilateur mettra en garde si une variable non initialisée est accessible, de sorte que je le vois que le résultat final est qu'il n'ya vraiment aucune excuse pour initialiser "juste au cas où".


0 commentaires