Question Est-ce que je lance le résultat de malloc?


Dans cette question, quelqu'un a suggéré dans un commentaire que je devrais ne pas jeter le résultat de malloc, c'est à dire.

int *sieve = malloc(sizeof(int) * length);

plutôt que:

int *sieve = (int *) malloc(sizeof(int) * length);

Pourquoi cela serait-il le cas?


2039
2018-03-03 10:13


origine


Réponses:


Non; toi ne pas jette le résultat, puisque:

  • Il est inutile, comme void * est promu automatiquement et en toute sécurité vers tout autre type de pointeur dans ce cas.
  • Il ajoute du fouillis au code, les lancers ne sont pas très faciles à lire (surtout si le type de pointeur est long).
  • Cela vous fait répéter, ce qui est généralement mauvais.
  • Il peut masquer une erreur si vous avez oublié d'inclure <stdlib.h>. Cela peut causer des accidents (ou, pire, ne pas causer un accident jusqu'à plus tard dans une partie totalement différente du code). Considérez ce qui se passe si les pointeurs et les entiers sont de taille différente; alors vous cachez un avertissement en moulant et pourriez perdre des morceaux de votre adresse retournée. Note: à partir de C11, les fonctions implicites sont passées de C, et ce point n'est plus pertinent car il n'y a pas d'hypothèse automatique que les fonctions non déclarées reviennent int.

A titre d'éclaircissement, notez que j'ai dit "vous ne lancez pas", pas "vous ne avoir besoin À mon avis, c'est un échec d'inclure le casting, même si vous l'avez bien fait. Il n'y a simplement aucun avantage à le faire, mais un tas de risques potentiels, y compris la distribution indique que vous ne savez pas sur les risques.

Notez également, comme le soulignent les commentateurs, que ce qui précède parle de droit C, pas de C ++. Je crois fermement en C et C ++ en tant que langues séparées.

Pour ajouter plus loin, votre code répète inutilement les informations de type (int) qui peut provoquer des erreurs. Il est préférable de déréférencer le pointeur utilisé pour stocker la valeur de retour, pour "verrouiller" les deux ensemble:

int *sieve = malloc(length * sizeof *sieve);

Cela déplace également le length à l'avant pour une meilleure visibilité, et supprime les parenthèses redondantes avec sizeof; ils sont seulement nécessaires lorsque l'argument est un nom de type. Beaucoup de gens semblent ne pas savoir (ou ignorer) ceci, ce qui rend leur code plus verbeux. Rappelles toi: sizeof n'est pas une fonction! :)


En bougeant length à l'avant mai augmenter la visibilité dans certains cas rares, il faut aussi faire attention que dans le cas général, il vaut mieux écrire l'expression comme:

int *sieve = malloc(sizeof *sieve * length);

Depuis le maintien du sizeof d'abord, dans ce cas, assure la multiplication est faite avec au moins size_t math.

Comparer: malloc(sizeof *sieve * length * width) contre. malloc(length * width * sizeof *sieve) la seconde peut déborder le length * width quand width et length sont des types plus petits que size_t.


1915
2018-03-03 10:17



En C, vous n'avez pas besoin de convertir la valeur de retour de malloc. Le pointeur sur void retourné par malloc est converti automagiquement au type correct. Cependant, si vous voulez que votre code soit compilé avec un compilateur C ++, un cast est nécessaire. Une alternative préférée parmi la communauté est d'utiliser ce qui suit:

int *sieve = malloc(sizeof *sieve * length);

ce qui vous libère en outre de devoir vous soucier de changer le côté droit de l'expression si jamais vous changez le type de sieve.

Les plâtres sont mauvais, comme les gens l'ont souligné. Moules de pointeur spécial.


327
2018-03-03 10:17



Toi faire jeter, parce que:

  • Il fait votre code plus portable entre C et C ++, et comme le montre l'expérience SO, un grand nombre de programmeurs affirment qu'ils écrivent en C lorsqu'ils écrivent réellement en C ++ (ou C plus les extensions de compilateurs locales).
  • Ne pas le faire peut cacher une erreur: notez tous les exemples de confusion de quand écrire type * contre type **.
  • L'idée qu'il vous empêche de vous remarquer n'a pas réussi à #include un fichier d'en-tête approprié manque la forêt pour les arbres. C'est la même chose que de dire "ne vous inquiétez pas du fait que vous n'avez pas demandé au compilateur de se plaindre de ne pas voir de prototypes - que stdlib.h embêtant est la VRAIE chose à retenir!"
  • Cela force un vérification croisée cognitive supplémentaire. Il met le type (présumé) désiré juste à côté de l'arithmétique que vous faites pour la taille brute de cette variable. Je parie que vous pourriez faire une étude SO qui montre que malloc() les bugs sont attrapés beaucoup plus vite quand il y a un casting. Comme pour les assertions, les annotations qui révèlent l'intention diminuent les bogues.
  • Se répéter d'une manière que la machine peut vérifier est souvent un génial idée. En fait, c'est ce qu'est une affirmation, et cette utilisation de la distribution est une assertion. Les assertions sont toujours la technique la plus générale que nous ayons pour obtenir un code correct, puisque Turing a eu l'idée il y a tant d'années.

291
2018-02-14 16:15



Comme mentionné précédemment, il n'est pas nécessaire pour C, mais pour C ++. Si vous pensez que vous allez compiler votre code C avec un compilateur C ++, pour quelles raisons, vous pouvez utiliser une macro à la place, comme:

#ifdef __cplusplus
# define NEW(type, count) ((type *)calloc(count, sizeof(type)))
#else
# define NEW(type, count) (calloc(count, sizeof(type)))
#endif

De cette façon, vous pouvez toujours l'écrire de manière très compacte:

int *sieve = NEW(int, 1);

et il compilera pour C et C ++.


148
2018-03-03 11:17



Du Wikipédia

Avantages à la coulée

  • Y compris la distribution peut permettre à un programme C ou une fonction de compiler en C ++.

  • La distribution permet les versions antérieures à 1989 de malloc qui renvoyait à l'origine un caractère *.

  • Le moulage peut aider le développeur à identifier les incohérences dans le dimensionnement si le type de pointeur de destination change, en particulier si le pointeur est déclaré loin de l'appel malloc () (bien que les compilateurs modernes et les analyseurs statiques puissent avertir d'un tel comportement).

Inconvénients à la coulée

  • Selon la norme ANSI C, la distribution est redondante.

  • Ajout de la distribution peut masquer l'échec d'inclure l'en-tête stdlib.h, dans   que le prototype de malloc est trouvé. En l'absence d'un   prototype pour malloc, la norme exige que le compilateur C   Supposons que malloc renvoie un int. S'il n'y a pas de distribution, un avertissement est   émis lorsque cet entier est assigné au pointeur; cependant, avec   le casting, cet avertissement n'est pas produit, cachant un bug. Sur certains   architectures et des modèles de données (tels que LP64 sur les systèmes 64 bits, où   long et les pointeurs sont 64 bits et int est 32 bits), cette erreur peut   effectivement entraîner un comportement indéfini, comme implicitement déclaré   malloc renvoie une valeur de 32 bits alors que la fonction réellement définie   renvoie une valeur 64 bits. Selon les conventions d'appel et la mémoire   mise en page, cela peut entraîner une destruction de la pile. Ce problème est moins probable   passer inaperçu dans les compilateurs modernes, car ils produisent uniformément   avertissements qu'une fonction non déclarée a été utilisée, un avertissement   apparaissent toujours. Par exemple, le comportement par défaut de GCC est de montrer   avertissement qui lit "déclaration implicite incompatible de built-in   fonction "indépendamment du fait que le casting est présent ou non.

  • Si le type du pointeur est modifié à sa déclaration, on peut   aussi, besoin de changer toutes les lignes où malloc est appelé et cast.

Bien que malloc sans casting est la méthode préférée et les programmeurs les plus expérimentés la choisissent, vous devriez utiliser ce que vous aimez avoir au courant des problèmes.

i.e: Si vous avez besoin de compiler le programme C en C ++ (Bien que ce soit un langage séparé), vous devez utiliser malloc avec casting.


95
2017-10-09 21:23



En C, vous pouvez implicitement convertir un pointeur vide en n'importe quel autre type de pointeur, donc un cast n'est pas nécessaire. L'utilisation d'un peut suggérer à l'observateur occasionnel qu'il y a une raison pour laquelle on en a besoin, ce qui peut être trompeur.


94
2018-03-03 10:18



Vous ne lancez pas le résultat de malloc, car cela ajoute un fouillis inutile à votre code.

La raison la plus courante pour laquelle les gens attribuent le résultat de malloc est qu'ils ne savent pas très bien comment le langage C fonctionne. C'est un signe d'avertissement: si vous ne savez pas comment un mécanisme de langue particulier fonctionne, alors ne pas devinez Regardez-le ou demandez sur Stack Overflow.

Certains commentaires:

  • Un pointeur vide peut être converti de / vers n'importe quel autre type de pointeur sans un cast explicite (C11 6.3.2.3 et 6.5.16.1).

  • C ++ ne permettra cependant pas une distribution implicite entre void* et un autre type de pointeur. Donc en C ++, la distribution aurait été correcte. Mais si vous programmez en C ++, vous devriez utiliser new et pas malloc (). Et vous ne devriez jamais compiler du code C en utilisant un compilateur C ++.

    Si vous devez prendre en charge C et C ++ avec le même code source, utilisez les commutateurs de compilateur pour marquer les différences. N'essayez pas d'utiliser les deux normes de langue avec le même code, car elles ne sont pas compatibles.

  • Si un compilateur C ne peut pas trouver une fonction parce que vous avez oublié d'inclure l'en-tête, vous obtiendrez une erreur de compilateur / éditeur de liens à ce sujet. Donc, si vous avez oublié d'inclure <stdlib.h> ce n'est pas grave, vous ne serez pas en mesure de construire votre programme.

  • Sur les anciens compilateurs qui suivent une version de la norme qui a plus de 25 ans, oublier d'inclure <stdlib.h> entraînerait un comportement dangereux. Parce que dans cette ancienne norme, les fonctions sans prototype visible convertissent implicitement le type de retour en int. Lancer le résultat de malloc explicitement cacherait alors ce bug.

    Mais c'est vraiment un non-problème. Vous n'utilisez pas un ordinateur vieux de 25 ans, alors pourquoi utiliser un compilateur de 25 ans?


83
2018-03-20 15:53



En C vous obtenez une conversion implicite de void* à tout autre pointeur (de données).


82
2018-03-03 10:16



Casting la valeur retournée par malloc() n'est pas nécessaire maintenant, mais j'aimerais ajouter un point qui semble ne pas l'être:

Dans les jours anciens, c'est avant ANSI C fournit le void * comme le type générique de pointeurs, char * est le type pour un tel usage. Dans ce cas, la distribution peut arrêter les avertissements du compilateur.

Référence: C FAQ


62
2018-06-09 17:31



Il n'est pas obligatoire de diffuser les résultats de malloc, puisqu'il revient void* et un void*peut être pointé vers n'importe quel type de données.


48
2018-02-07 22:22



Juste en ajoutant mon expérience, en étudiant l'ingénierie informatique je vois que les deux ou trois professeurs que j'ai vu écrire en C ont toujours lancé malloc, mais celui que j'ai demandé (avec un CV immense et une compréhension de C) m'a dit que c'était absolument inutile seulement utilisé pour être absolument spécifique, et pour amener les étudiants dans la mentalité d'être absolument spécifique. Fondamentalement, le moulage ne changera rien à son fonctionnement, il fait exactement ce qu'il dit, alloue de la mémoire, et le moulage ne l'affecte pas, vous obtenez la même mémoire, et même si vous le transzidez par erreur (et évitez en quelque sorte le compilateur erreurs) C y accédera de la même manière.

Modifier: Le casting a un certain point. Lorsque vous utilisez la notation de tableau, le code généré doit connaître le nombre d'emplacements de mémoire qu'il doit avancer pour atteindre le début de l'élément suivant. De cette façon, vous savez que pour un double vous avancez de 8 octets, alors que pour un int vous allez 4, et ainsi de suite. Ainsi, il n'a aucun effet si vous utilisez la notation par pointeur, dans la notation de tableau, il devient nécessaire.


44
2018-03-28 18:21