Dois-je lancer le résultat de malloc?

Mar 03 2009

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

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

plutôt que:

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

Pourquoi serait-ce le cas?

Réponses

2285 unwind Mar 03 2009 at 17:17

Non ; vous ne lancez pas le résultat, car:

  • Il n'est pas nécessaire, comme cela void *est automatiquement et en toute sécurité promu à tout autre type de pointeur dans ce cas.
  • Cela ajoute du fouillis au code, les casts ne sont pas très faciles à lire (surtout si le type de pointeur est long).
  • Cela vous fait vous 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 provoquer des plantages (ou, pire, ne pas provoquer de plantage que bien 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 castant et vous risquez de perdre des morceaux de votre adresse renvoyée. Remarque: à partir de C99, les fonctions implicites ont disparu 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 retournent int.

Pour clarifier, notez que j'ai dit "vous ne lancez pas", pas "vous n'avez pas besoin de lancer". À mon avis, c'est un échec d'inclure le casting, même si vous avez bien compris. Il n'y a tout simplement aucun avantage à le faire, mais un tas de risques potentiels, et y compris le casting indique que vous ne connaissez pas les risques.

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

Pour ajouter plus, votre code répète inutilement les informations de type ( int), ce 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 lengthvers l'avant pour une visibilité accrue et supprime les parenthèses redondantes avec sizeof; ils ne sont nécessaires que lorsque l'argument est un nom de type. Beaucoup de gens semblent ne pas savoir (ou ignorer) cela, ce qui rend leur code plus détaillé. N'oubliez pas: ce sizeofn'est pas une fonction! :)


Bien que le déplacement lengthvers l'avant puisse augmenter la visibilité dans certains cas rares, il faut également faire attention au fait que dans le cas général, il devrait être préférable d'écrire l'expression comme suit:

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

Depuis garder le sizeofpremier, dans ce cas, garantit que la multiplication est faite avec au moins les size_tmathématiques.

Comparez: malloc(sizeof *sieve * length * width)vs malloc(length * width * sizeof *sieve)le second peut déborder le length * widthquand widthet lengthsont des types plus petits que size_t.

387 dirkgently Mar 03 2009 at 17:17

En C, vous n'avez pas besoin de convertir la valeur de retour de malloc. Le pointeur vers void renvoyé par mallocest automatiquement converti dans le type correct. Cependant, si vous souhaitez que votre code compile 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 évite en outre d'avoir à vous soucier de changer le côté droit de l'expression si jamais vous changez le type de sieve.

Les moulages sont mauvais, comme les gens l'ont souligné. Surtout les lancers de pointeurs.

360 RonBurk Feb 14 2013 at 23:15

Vous faites du casting, car:

  • Cela rend 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 alors qu'ils écrivent vraiment en C ++ (ou C plus les extensions de compilateur local).
  • Ne pas le faire peut masquer une erreur : notez tous les exemples SO de confusion entre quand écrire type *et quand type **.
  • L'idée que cela vous empêche de remarquer que vous avez échoué dans #includeun 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 les prototypes - ce stdlib.h embêtant est la VRAIE chose importante à retenir!"
  • Cela force un contrôle croisé cognitif supplémentaire . Il place le type souhaité (prétendu) 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 les malloc()bugs sont détectés beaucoup plus rapidement quand il y a un casting. Comme pour les assertions, les annotations qui révèlent l'intention réduisent les bogues.
  • Se répéter d'une manière que la machine peut vérifier est souvent une excellente idée. En fait, c'est ce qu'est une assertion, et cette utilisation de cast est une assertion. Les assertions sont toujours la technique la plus générale dont nous disposons pour obtenir un code correct, depuis que Turing a eu l'idée il y a tant d'années.
174 quinmars Mar 03 2009 at 18:17

Comme d'autres l'ont indiqué, ce n'est pas nécessaire pour C, mais nécessaire pour C ++. Si vous pensez que vous allez compiler votre code C avec un compilateur C ++, pour quelque raison que ce soit, 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 ++.

146 ashiquzzaman33 Oct 10 2015 at 04:23

Sur Wikipédia :

Avantages de la coulée

  • L'inclusion de la distribution peut permettre à un programme ou à une fonction C de se compiler en C ++.

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

  • La conversion peut aider le développeur à identifier les incohérences dans le dimensionnement du type 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 sans nécessiter la conversion).

Inconvénients du casting

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

  • L'ajout de la distribution peut masquer l'échec de l'inclusion de l'en-tête stdlib.h , dans lequel se trouve le prototype de malloc. En l'absence de prototype pour malloc, la norme exige que le compilateur C suppose que malloc renvoie un int. S'il n'y a pas de conversion, un avertissement est émis lorsque cet entier est affecté au pointeur; cependant, avec le casting, cet avertissement n'est pas produit, cachant un bug. Sur certaines architectures et modèles de données (comme LP64 sur les systèmes 64 bits, où long et pointeurs sont 64 bits et int est 32 bits), cette erreur peut en fait entraîner un comportement indéfini, car le malloc déclaré implicitement renvoie un 32- valeur de bit alors que la fonction réellement définie renvoie une valeur de 64 bits. Selon les conventions d'appel et la disposition de la mémoire, cela peut entraîner un écrasement de la pile. Ce problème est moins susceptible de passer inaperçu dans les compilateurs modernes, car ils produisent uniformément des avertissements qu'une fonction non déclarée a été utilisée, donc un avertissement apparaîtra toujours. Par exemple, le comportement par défaut de GCC est d'afficher un avertissement qui lit "déclaration implicite incompatible de fonction intégrée", que le cast soit présent ou non.

  • Si le type du pointeur est modifié lors de sa déclaration, il peut également être nécessaire de modifier toutes les lignes où malloc est appelé et cast.

Bien que malloc sans casting soit la méthode préférée et que la plupart des programmeurs expérimentés la choisissent , vous devez utiliser celle que vous souhaitez avoir au courant des problèmes.

ie: Si vous avez besoin de compiler un programme C en C ++ (bien que ce soit un langage séparé), vous devez convertir le résultat de l'utilisation malloc.

108 PaulJWilliams Mar 03 2009 at 17:18

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

104 Lundin Mar 20 2014 at 22:53

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

La raison la plus courante pour laquelle les gens lancent le résultat de mallocest parce qu'ils ne sont pas sûrs du fonctionnement du langage C. C'est un signe d'avertissement: si vous ne savez pas comment fonctionne un mécanisme de langage particulier, ne faites pas de supposition. Recherchez-le ou demandez-le sur Stack Overflow.

Certains commentaires:

  • Un pointeur void peut être converti vers / à partir de tout autre type de pointeur sans conversion explicite (C11 6.3.2.3 et 6.5.16.1).

  • C ++ n'autorisera cependant pas une conversion implicite entre void*et un autre type de pointeur. Donc en C ++, la distribution aurait été correcte. Mais si vous programmez en C ++, vous devez utiliser newet non malloc(). Et vous ne devez jamais compiler du code C à l'aide d'un compilateur C ++.

    Si vous devez prendre en charge à la fois C et C ++ avec le même code source, utilisez les commutateurs du compilateur pour marquer les différences. N'essayez pas de remplir les deux normes linguistiques 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 du compilateur / éditeur de liens à ce sujet. Donc, si vous avez oublié d'inclure <stdlib.h>ce n'est pas grave, vous ne pourrez pas créer 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 convertissaient implicitement le type de retour en int. Le cast du résultat de mallocexplicitement masquerait alors ce bogue.

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

95 EFraim Mar 03 2009 at 17:16

En C, vous obtenez une conversion implicite de void *vers n'importe quel autre pointeur (de données).

72 YuHao Jun 10 2013 at 00:31

Le cast de la valeur renvoyée par malloc()n'est pas nécessaire maintenant, mais j'aimerais ajouter un point qui semble que personne ne l'ait souligné:

Dans les temps anciens, c'est-à-dire avant que ANSI C ne fournisse le void *type générique de pointeurs, char *c'est le type pour une telle utilisation. Dans ce cas, la distribution peut arrêter les avertissements du compilateur.

Référence: C FAQ

55 user3079666 Mar 29 2014 at 01:21

En ajoutant simplement mon expérience, en étudiant l'ingénierie informatique, je vois que les deux ou trois professeurs que j'ai vus écrire en C ont toujours jeté 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 mais Auparavant, c'était seulement absolument spécifique, et pour amener les étudiants dans la mentalité d'être absolument spécifiques. Essentiellement, le casting ne changera rien à son fonctionnement, il fait exactement ce qu'il dit, alloue de la mémoire et le casting ne l'affecte pas, vous obtenez la même mémoire, et même si vous le convertissez en autre chose par erreur (et en quelque sorte échapper au compilateur erreurs) C y accèdera de la même manière.

Edit: Casting a un certain point. Lorsque vous utilisez la notation de tableau, le code généré doit savoir combien de places de mémoire il doit avancer pour atteindre le début de l'élément suivant, ceci est réalisé par la conversion. De cette façon, vous savez que pour un double, vous avancez de 8 octets tandis que pour un int, vous allez 4, et ainsi de suite. Ainsi, cela n'a aucun effet si vous utilisez la notation pointeur, en notation tableau, cela devient nécessaire.

53 user968000 Feb 08 2013 at 05:22

Il n'est pas obligatoire de convertir les résultats de malloc, car il retourne void*, et a void*peut être pointé vers n'importe quel type de données.

37 Slothworks Oct 10 2015 at 00:47

Voici ce que dit le manuel de référence de la bibliothèque GNU C :

Vous pouvez stocker le résultat de mallocdans n'importe quelle variable de pointeur sans conversion, car ISO C convertit automatiquement le type void *en un autre type de pointeur si nécessaire. Mais le cast est nécessaire dans des contextes autres que les opérateurs d'affectation ou si vous souhaitez que votre code s'exécute en C.

Et en effet, la norme ISO C11 (p347) le dit:

Le pointeur renvoyé si l'allocation réussit est correctement aligné de sorte qu'il puisse être attribué à un pointeur vers tout type d'objet avec une exigence d'alignement fondamentale, puis utilisé pour accéder à un tel objet ou à un tableau de tels objets dans l'espace alloué (jusqu'à ce que le l'espace est explicitement désalloué)

35 Endeavour Jul 13 2014 at 13:42

Un pointeur void est un pointeur d'objet générique et C prend en charge la conversion implicite d'un type pointeur void vers d'autres types, il n'est donc pas nécessaire de le typer explicitement.

Cependant, si vous voulez que le même code fonctionne parfaitement compatible sur une plate-forme C ++, qui ne prend pas en charge la conversion implicite, vous devez faire le transtypage, donc tout dépend de la convivialité.

30 swaps Apr 26 2013 at 23:43

Le type renvoyé est void *, qui peut être converti en le type souhaité de pointeur de données afin d'être déréférencable.

29 Jeyamaran Mar 17 2014 at 20:16

Cela dépend du langage de programmation et du compilateur. Si vous utilisez mallocen C, il n'est pas nécessaire de taper cast it, car il tapera automatiquement cast. Cependant, si vous utilisez C ++, vous devez taper cast car mallocretournera un void*type.

28 AugustKarlstrom Sep 04 2015 at 18:52

Dans le langage C, un pointeur void peut être affecté à n'importe quel pointeur, c'est pourquoi vous ne devez pas utiliser de cast de type. Si vous souhaitez une allocation "type safe", je peux vous recommander les fonctions de macro suivantes, que j'utilise toujours dans mes projets C:

#include <stdlib.h>
#define NEW_ARRAY(ptr, n) (ptr) = malloc((n) * sizeof *(ptr))
#define NEW(ptr) NEW_ARRAY((ptr), 1)

Avec ceux-ci en place, vous pouvez simplement dire

NEW_ARRAY(sieve, length);

Pour les tableaux non dynamiques, la troisième macro de fonction indispensable est

#define LEN(arr) (sizeof (arr) / sizeof (arr)[0])

ce qui rend les boucles de tableau plus sûres et plus pratiques:

int i, a[100];

for (i = 0; i < LEN(a); i++) {
   ...
}
18 StephenG Dec 05 2015 at 00:27

Les gens habitués à GCC et Clang sont gâtés. Ce n'est pas si bon là-bas.

J'ai été assez horrifié au fil des ans par les compilateurs incroyablement âgés que j'ai dû utiliser. Souvent, les entreprises et les gestionnaires adoptent une approche ultra-conservatrice pour changer de compilateur et ne testeront même pas si un nouveau compilateur (avec une meilleure conformité aux normes et une optimisation du code) fonctionnera dans leur système. La réalité pratique pour les développeurs qui travaillent est que lorsque vous codez, vous devez couvrir vos bases et, malheureusement, lancer des mallocs est une bonne habitude si vous ne pouvez pas contrôler quel compilateur peut être appliqué à votre code.

Je suggérerais également que de nombreuses organisations appliquent leur propre norme de codage et que ce soit la méthode que les gens suivent si elle est définie. En l'absence de directives explicites, j'ai tendance à opter pour le plus susceptible de compiler partout, plutôt que l'adhésion servile à une norme.

L'argument selon lequel ce n'est pas nécessaire selon les normes actuelles est tout à fait valable. Mais cet argument omet les aspects pratiques du monde réel. Nous ne codons pas dans un monde régi exclusivement par la norme du jour, mais par les aspects pratiques de ce que j'aime appeler «le champ de réalité du management local». Et c'est plié et tordu plus que l'espace-temps ne l'a jamais été. :-)

YMMV.

J'ai tendance à penser à lancer malloc comme une opération défensive. Pas joli, pas parfait, mais généralement sûr. (Honnêtement, si vous n'avez pas inclus stdlib.h, vous avez bien plus de problèmes que de lancer malloc!).

16 Noname Aug 16 2017 at 19:25

Non, vous ne lancez pas le résultat de malloc().

En général, vous nevoid * lancez pas vers ou depuis .

Une raison typique invoquée pour ne pas le faire est que le fait de #include <stdlib.h>ne pas le faire pourrait passer inaperçu. Ce n'est plus un problème depuis longtemps car C99 a rendu les déclarations de fonctions implicites illégales, donc si votre compilateur est conforme au moins à C99, vous obtiendrez un message de diagnostic.

Mais il y a une raison beaucoup plus forte de ne pas introduire de lancers de pointeurs inutiles:

En C, un cast de pointeur est presque toujours une erreur . Ceci est dû à la règle suivante ( §6.5 p7 dans N1570, le dernier projet pour C11):

Un objet ne doit avoir accès à sa valeur stockée que par une expression lvalue qui a l'un des types suivants:
- un type compatible avec le type effectif de l'objet,
- une version qualifiée d'un type compatible avec le type effectif de l'objet,
- un type qui est le type signé ou non signé correspondant au type effectif de l'objet,
- un type qui est le type signé ou non signé correspondant à une version qualifiée du type effectif de l'objet,
- un type d'agrégat ou d'union qui en inclut un des types susmentionnés parmi ses membres (y compris, de manière récursive, un membre d'une union sous-agrégée ou contenue), ou
- un type de caractère.

Ceci est également connu sous le nom de règle stricte d'aliasing . Le code suivant est donc un comportement indéfini :

long x = 5;
double *p = (double *)&x;
double y = *p;

Et, parfois étonnamment, ce qui suit est aussi:

struct foo { int x; };
struct bar { int x; int y; };
struct bar b = { 1, 2};
struct foo *p = (struct foo *)&b;
int z = p->x;

, Parfois vous ne devez pointeurs de la distribution, mais étant donné la règle stricte de aliasing , vous devez être très prudent avec elle. Ainsi, toute occurrence d'un pointeur moulé dans votre code est un endroit où vous devez vérifier sa validité . Par conséquent, vous n'écrivez jamais un cast de pointeur inutile.

tl; dr

En un mot: étant donné qu'en C, toute occurrence d'un cast de pointeur doit déclencher un drapeau rouge pour le code nécessitant une attention particulière, vous ne devez jamais écrire de casts de pointeur inutiles .


Notes secondaires:

  • Il y a des cas où vous avez réellement besoin d' un cast void *, par exemple si vous voulez imprimer un pointeur:

    int x = 5;
    printf("%p\n", (void *)&x);
    

    Le cast est nécessaire ici, car il printf()s'agit d'une fonction variadique, donc les conversions implicites ne fonctionnent pas.

  • En C ++, la situation est différente. Le cast des types de pointeurs est assez courant (et correct) lorsqu'il s'agit d'objets de classes dérivées. Par conséquent, il est logique qu'en C ++, la conversion vers et depuis nevoid * soit pas implicite. C ++ a tout un ensemble de différentes saveurs de casting.

15 Kaz Mar 30 2016 at 07:23

J'ai mis dans le casting simplement pour montrer la désapprobation du vilain trou dans le système de types, qui permet à un code tel que l'extrait suivant de se compiler sans diagnostic, même si aucun cast n'est utilisé pour provoquer la mauvaise conversion:

double d;
void *p = &d;
int *q = p;

Je souhaite que cela n'existait pas (et ce n'est pas le cas en C ++) et j'ai donc casté. Cela représente mon goût et ma politique de programmation. Je ne fais pas que lancer un pointeur, mais effectivement, je dépose un bulletin de vote et chasse les démons de la stupidité . Si je ne peux pas vraiment chasser la stupidité , alors laissez-moi au moins exprimer le souhait de le faire avec un geste de protestation.

En fait, une bonne pratique consiste à envelopper malloc(et les amis) avec des fonctions qui retournent unsigned char *, et essentiellement de ne jamais les utiliser void *dans votre code. Si vous avez besoin d'un pointeur générique vers n'importe quel objet, utilisez un char *ou unsigned char *et effectuez des casts dans les deux directions. La seule relaxation qui peut être offerte, peut-être, utilise des fonctions telles que memsetet memcpysans moulages.

Sur le sujet de la conversion et de la compatibilité C ++, si vous écrivez votre code pour qu'il se compile à la fois en C et en C ++ (auquel cas vous devez convertir la valeur de retour de malloclorsque vous l'assignez à autre chose que void *), vous pouvez faire un très utile chose pour vous-même: vous pouvez utiliser des macros pour le cast qui se traduisent en casts de style C ++ lors de la compilation en C ++, mais se réduisent à un cast C lors de la compilation en C:

/* In a header somewhere */
#ifdef __cplusplus
#define strip_qual(TYPE, EXPR) (const_cast<TYPE>(EXPR))
#define convert(TYPE, EXPR) (static_cast<TYPE>(EXPR))
#define coerce(TYPE, EXPR) (reinterpret_cast<TYPE>(EXPR))
#else
#define strip_qual(TYPE, EXPR) ((TYPE) (EXPR))
#define convert(TYPE, EXPR) ((TYPE) (EXPR))
#define coerce(TYPE, EXPR) ((TYPE) (EXPR))
#endif

Si vous adhérez à ces macros, une simple greprecherche de votre base de code pour ces identifiants vous montrera où se trouvent tous vos transtypages, afin que vous puissiez vérifier si l'un d'entre eux est incorrect.

Ensuite, à l'avenir, si vous compilez régulièrement le code avec C ++, cela imposera l'utilisation d'un cast approprié. Par exemple, si vous utilisez strip_qualjuste pour supprimer un constou volatile, mais que le programme change de telle sorte qu'une conversion de type est maintenant impliquée, vous obtiendrez un diagnostic et vous devrez utiliser une combinaison de casts pour obtenir la conversion souhaitée.

Pour vous aider à adhérer à ces macros, le compilateur GNU C ++ (et non C!) A une belle fonctionnalité: un diagnostic optionnel qui est produit pour toutes les occurrences de casts de style C.

     -Wold-style-cast (C ++ et Objective-C ++ uniquement)
         Avertir si un cast de style ancien (style C) en un type non vide est utilisé
         dans un programme C ++. Les moulages de style nouveau (dynamic_cast,
         static_cast, reinterpret_cast et const_cast) sont moins vulnérables
         aux effets inattendus et beaucoup plus facile à rechercher.

Si votre code C se compile en C ++, vous pouvez utiliser cette -Wold-style-castoption pour découvrir toutes les occurrences de la (type)syntaxe de conversion qui peuvent s'insinuer dans le code, et faire le suivi de ces diagnostics en le remplaçant par un choix approprié parmi les macros ci-dessus (ou un combinaison, si nécessaire).

Ce traitement des conversions est la plus grande justification technique autonome pour travailler dans un «C propre»: le dialecte combiné C et C ++, qui à son tour justifie techniquement la conversion de la valeur de retour de malloc.

15 proski Jun 29 2016 at 14:30

Je préfère faire le casting, mais pas manuellement. Mon préféré est l'utilisation g_newet les g_new0macros de glib. Si glib n'est pas utilisé, j'ajouterais des macros similaires. Ces macros réduisent la duplication de code sans compromettre la sécurité des types. Si vous obtenez un type incorrect, vous obtiendrez un cast implicite entre des pointeurs non vides, ce qui provoquerait un avertissement (erreur en C ++). Si vous oubliez d'inclure l'en-tête qui définit g_newet g_new0, vous obtiendrez une erreur. g_newet les g_new0deux prennent les mêmes arguments, contrairement à mallocqui prend moins d'arguments que calloc. Ajoutez simplement 0pour obtenir une mémoire initialisée à zéro. Le code peut être compilé avec un compilateur C ++ sans modifications.

14 user877329 Jun 12 2015 at 22:23

La meilleure chose à faire lors de la programmation en C chaque fois que c'est possible:

  1. Faites compiler votre programme via un compilateur C avec tous les avertissements activés -Wallet corrigez toutes les erreurs et avertissements
  2. Assurez-vous qu'aucune variable n'est déclarée comme auto
  3. Puis compilez-le à l'aide d'un compilateur C ++ avec -Wallet -std=c++11. Corrigez toutes les erreurs et avertissements.
  4. Maintenant, compilez à nouveau en utilisant le compilateur C. Votre programme devrait maintenant compiler sans aucun avertissement et contenir moins de bogues.

Cette procédure vous permet de profiter de la vérification de type stricte C ++, réduisant ainsi le nombre de bogues. En particulier, cette procédure vous oblige à inclure stdlib.hou vous obtiendrez

malloc n'a pas été déclaré dans ce périmètre

et vous oblige également à lancer le résultat de mallocou vous obtiendrez

conversion incorrecte de void*àT*

ou quel que soit votre type de cible.

Les seuls avantages de l'écriture en C au lieu de C ++ que je peux trouver sont

  1. C a un ABI bien spécifié
  2. C ++ peut générer plus de code [exceptions, RTTI, modèles, polymorphisme d' exécution ]

Notez que le deuxième inconvénient devrait dans le cas idéal disparaître lors de l'utilisation du sous-ensemble commun à C avec la fonction polymorphe statique .

Pour ceux qui trouvent les règles strictes C ++ peu pratiques, nous pouvons utiliser la fonctionnalité C ++ 11 avec le type inféré

auto memblock=static_cast<T*>(malloc(n*sizeof(T))); //Mult may overflow...
12 Noname Sep 10 2015 at 22:58

Le casting est uniquement pour C ++ et non C. Dans le cas où vous utilisez un compilateur C ++, vous feriez mieux de le changer en compilateur C.

10 Aashish Oct 03 2017 at 20:13

Le casting de malloc est inutile en C mais obligatoire en C ++.

La diffusion est inutile en C à cause de:

  • void * est automatiquement et en toute sécurité promu à tout autre type de pointeur dans le cas de C.
  • Il peut masquer une erreur si vous avez oublié d'inclure <stdlib.h>. Cela peut provoquer des plantages.
  • Si les pointeurs et les entiers sont de taille différente, vous masquez un avertissement en castant et vous risquez de perdre des bits de votre adresse renvoyée.
  • Si le type du pointeur est changé lors de sa déclaration, il peut également être nécessaire de changer toutes les lignes où mallocest appelé et cast.

D'un autre côté, la diffusion peut augmenter la portabilité de votre programme. c'est-à-dire qu'il permet à un programme ou à une fonction C de se compiler en C ++.

9 iec2011007 Jul 29 2015 at 12:53

Le concept derrière le pointeur void est qu'il peut être converti en n'importe quel type de données, c'est pourquoi malloc renvoie void. Vous devez également être conscient de la conversion de type automatique. Il n'est donc pas obligatoire de lancer le pointeur mais vous devez le faire. Cela aide à garder le code propre et aide au débogage

9 dhanagovindarajan Jul 18 2016 at 17:36

Un pointeur void est un pointeur générique et C prend en charge la conversion implicite d'un type pointeur void vers d'autres types, il n'est donc pas nécessaire de le typer explicitement.

Cependant, si vous voulez que le même code fonctionne parfaitement compatible sur une plate-forme C ++, qui ne prend pas en charge la conversion implicite, vous devez faire le transtypage, donc tout dépend de la convivialité.

9 Mohit Nov 08 2016 at 17:09
  1. Comme d'autres l'ont indiqué, il n'est pas nécessaire pour C, mais pour C ++.

  2. L'inclusion de la distribution peut permettre à un programme ou à une fonction C de se compiler en C ++.

  3. En C, ce n'est pas nécessaire, car void * est automatiquement et en toute sécurité promu vers n'importe quel autre type de pointeur.

  4. Mais si vous lancez alors, il peut masquer une erreur si vous avez oublié d'inclure stdlib.h . Cela peut provoquer des plantages (ou, pire, ne pas provoquer de plantage que bien plus tard dans une partie totalement différente du code).

    Parce que stdlib.h contient le prototype de malloc est trouvé. En l'absence de prototype pour malloc, la norme exige que le compilateur C suppose que malloc renvoie un int. S'il n'y a pas de conversion, un avertissement est émis lorsque cet entier est affecté au pointeur; cependant, avec le casting, cet avertissement n'est pas produit, cachant un bug.

4 RobertSsupportsMonicaCellio Jun 13 2020 at 02:20

Cette question fait l'objet d'abus d'opinion.

Parfois, je remarque des commentaires comme ça:

Ne lancez pas le résultat de malloc

ou

Pourquoi vous ne lancez pas le résultat de malloc

sur les questions où OP utilise le casting. Les commentaires eux-mêmes contiennent un hyperlien vers cette question.

Cela est également inapproprié et incorrect de quelque manière que ce soit. Il n'y a ni bien ni mal lorsqu'il s'agit vraiment de son propre style de codage.


Pourquoi cela arrive-t-il?

Il repose sur deux raisons:

  1. Cette question est en effet basée sur l'opinion. Techniquement, la question aurait dû être close comme basée sur l'opinion il y a des années. Une question « Dois-je » ou « Ne pas je » ou l'équivalent « Devrais-je » ou « Ne devrais-je pas », vous ne pouvez tout simplement pas répondre de manière ciblée sans une attitude de votre propre opinion. Une des raisons pour clore une question est qu'elle "peut conduire à des réponses basées sur l'opinion" comme cela est bien montré ici.

  2. De nombreuses réponses (y compris les plus apparente et acceptée réponse de @unwind ) sont soit entièrement ou presque entièrement fondée sur des opinions (fe un mystérieux « fouillis » qui serait ajouté à votre code si vous ne moulage ou vous répéter serait mauvais) et spectacle une tendance claire et ciblée à omettre le casting. Ils argumentent sur la redondance de la distribution d'un côté mais aussi et pire encore pour résoudre un bug causé par un bug / échec de la programmation elle-même - pas #include <stdlib.h>si l'on veut l'utiliser malloc().


Je veux apporter une vraie vision de certains points discutés, avec moins de mon opinion personnelle. Quelques points doivent être notés en particulier:

  1. Une telle question très susceptible de tomber dans sa propre opinion nécessite une réponse avec des avantages et des inconvénients neutres. Pas seulement des inconvénients ou des avantages.

    Un bon aperçu des avantages et des inconvénients est répertorié dans cette réponse:

    https://stackoverflow.com/a/33047365/12139179

    (Personnellement, je considère cela pour cette raison comme la meilleure réponse à ce jour.)


  1. Une des raisons rencontrées tout au plus pour expliquer l'omission du casting est que le casting pourrait cacher un bug.

    Si quelqu'un utilise une déclaration implicite malloc()qui renvoie int(les fonctions implicites ont disparu du standard depuis C99) et sizeof(int) != sizeof(int*), comme indiqué dans cette question

    Pourquoi ce code segfault sur l'architecture 64 bits mais fonctionne bien sur 32 bits?

    le casting cacherait un bug.

    Bien que cela soit vrai, cela ne montre que la moitié de l'histoire car l'omission de la distribution ne serait qu'une solution d'avenir à un bug encore plus important - non compris stdlib.hlors de l'utilisation malloc().

    Ce ne sera jamais un problème sérieux, si vous,

    1. Utilisez un compilateur conforme à C99 ou supérieur (ce qui est recommandé et devrait être obligatoire), et

    2. Ne stdlib.hsoyez pas si absent pour oublier d'inclure , lorsque vous voulez utiliser malloc()dans votre code, ce qui est un énorme bogue en soi.


  1. Certaines personnes discutent de la conformité C ++ du code C, car le cast est obligatoire en C ++.

    Tout d'abord à dire en général: compiler du code C avec un compilateur C ++ n'est pas une bonne pratique.

    C et C ++ sont en fait deux langages complètement différents avec une sémantique différente.

    Mais si vous voulez / avez vraiment besoin de rendre le code C compatible avec C ++ et vice versa, utilisez les commutateurs du compilateur au lieu de tout cast.

    Comme le casting est à tendance déclaré redondant voire nuisible, je souhaite me concentrer sur ces questions, qui donnent de bonnes raisons pour lesquelles le casting peut être utile voire nécessaire:

    • https://stackoverflow.com/a/34094068/12139179

    • https://stackoverflow.com/a/36297486/12139179

    • https://stackoverflow.com/a/33044300/12139179


  1. Le cast peut être inutile lorsque votre code, respectivement le type du pointeur assigné (et avec cela le type du cast), change, bien que cela soit dans la plupart des cas peu probable. Ensuite, vous devrez également maintenir / modifier tous les casts et si vous avez quelques milliers d'appels aux fonctions de gestion de la mémoire dans votre code, cela peut vraiment résumer et diminuer l'efficacité de la maintenance.

Sommaire:

Le fait est que la distribution est redondante selon la norme C (déjà depuis ANSI-C (C89 / C90)) si le pointeur assigné pointe vers un objet d'exigence d'alignement fondamental (qui comprend le plus de tous les objets).

Vous n'avez pas besoin de faire la distribution car le pointeur est automatiquement aligné dans ce cas:

"L'ordre et la contiguïté du stockage alloué par des appels successifs aux fonctions align_alloc, calloc, malloc et realloc ne sont pas spécifiés. Le pointeur renvoyé si l'allocation réussit est correctement aligné afin qu'il puisse être affecté à un pointeur vers n'importe quel type d'objet avec une exigence d'alignement fondamentale et ensuite utilisé pour accéder à un tel objet ou à un tableau de tels objets dans l'espace alloué (jusqu'à ce que l'espace soit explicitement désalloué). "

Source: C18, §7.22.3 / 1


"Un alignement fondamental est un alignement valide inférieur ou égal à _Alignof (max_align_t). Les alignements fondamentaux doivent être pris en charge par la mise en œuvre pour les objets de toutes les durées de stockage. Les exigences d'alignement des types suivants sont des alignements fondamentaux:

- tous les types de base atomiques, qualifiés ou non qualifiés;

- tous les types énumérés atomiques, qualifiés ou non qualifiés;

- tous les types de pointeurs atomiques, qualifiés ou non qualifiés;

- tous les types de tableaux dont le type d'élément a une exigence d'alignement fondamentale; 57)

- tous les types spécifiés dans l'Article 7 en tant que types d'objets complets;

- tous les types de structure ou d'union dont tous les éléments ont des types avec des exigences d'alignement fondamentales et dont aucun élément n'a de spécificateur d'alignement spécifiant un alignement qui n'est pas un alignement fondamental.

  1. Comme spécifié au 6.2.1, la déclaration ultérieure peut masquer la déclaration précédente. "

Source: C18, §6.2.8 / 2

Cependant, si vous allouez de la mémoire pour un objet défini par l'implémentation de l'exigence d'alignement étendu, le cast serait nécessaire.

Un alignement étendu est représenté par un alignement supérieur à _Alignof (max_align_t). Il est défini par l'implémentation si des alignements étendus sont pris en charge et les durées de stockage pour lesquelles ils sont pris en charge. Un type ayant une exigence d'alignement étendu est un type suraligné.58)

La source. C18, §6.2.8 / 3

Tout le reste dépend du cas d'utilisation spécifique et de sa propre opinion.

Veuillez faire attention à la manière dont vous vous éduquez.

Je vous recommande de lire attentivement toutes les réponses apportées jusqu'à présent (ainsi que leurs commentaires qui peuvent indiquer un échec), puis de vous forger votre propre opinion si vous ou si vous ne présentez pas le résultat d' malloc()un cas spécifique.

Notez s'il vous plaît:

Il n'y a pas de bonne et de mauvaise réponse à cette question. C'est une question de style et vous décidez vous-même de la voie que vous choisissez (si vous n'êtes pas obligé par l'éducation ou le travail bien sûr). Soyez conscient de cela et ne vous laissez pas tromper .


Dernière note: j'ai voté dernièrement pour clore cette question en tant qu'opinion, ce qui est effectivement nécessaire depuis des années. Si vous avez le privilège de fermeture / réouverture, je voudrais vous inviter à le faire également.

pasignature Mar 05 2020 at 22:56

Pour moi, le constat et la conclusion ici est que le casting mallocen C n'est absolument PAS nécessaire, mais si vous lancez cependant, cela n'affectera pas malloccar vous mallocallouerez toujours votre espace mémoire béni demandé. Une autre chose à retenir est la raison ou l'une des raisons pour lesquelles les gens font du casting et c'est pour leur permettre de compiler le même programme en C ou C ++.

Il peut y avoir d'autres raisons, mais d'autres raisons, presque certainement, vous poseraient de graves problèmes tôt ou tard.

ivan.ukr May 22 2020 at 14:03

Vous pouvez, mais vous n'avez pas besoin de convertir en C. Vous devez effectuer un cast si ce code est compilé en C ++.