web-dev-qa-db-fra.com

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

Dans cette question , quelqu'un a suggéré dans un commentaire que je devrais pas transforme 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 serait-ce le cas?

2285
Patrick McDonald

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

  • C'est inutile, car void * est automatiquement et sûrement promu en un autre type de pointeur dans ce cas.
  • Cela ajoute du fouillis au code, les transts 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.
  • Cela peut cacher une erreur si vous avez oublié d'inclure <stdlib.h>. Cela peut provoquer des plantages (ou, pire, et non causer un plantage 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 tailles différentes. alors vous cachez un avertissement en diffusant et vous risquez de perdre une partie de votre adresse renvoyée. Remarque: à partir de C11, les fonctions implicites sont passées de C et ce point n'est plus pertinent puisqu'il n'existe aucune hypothèse automatique selon laquelle les fonctions non déclarées renvoient int.

Pour clarifier, notez que j'ai dit "vous ne lancez pas", pas "vous n'avez pas besoin de pour lancer". À mon avis, c'est un échec pour inclure le casting, même si vous avez bien compris. Cela ne présente tout simplement aucun avantage, mais un ensemble de risques potentiels, et l'inclusion de la distribution 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, pas 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) qui peuvent provoquer des erreurs. Il est préférable de déréférencer le pointeur utilisé pour stocker la valeur de retour afin de "verrouiller" les deux ensembles:

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

Cela déplace également le length vers 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 verbeux. Rappelez-vous: sizeof n'est pas une fonction! :)


Tout en déplaçant length vers l'avant peut augmenter la visibilité dans certains cas rares, il convient également de noter que, dans le cas général, il convient de: mieux écrire l'expression comme:

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

Puisque garder la sizeof en premier, dans ce cas, assure que la multiplication est faite avec au moins size_t math.

Comparez: malloc(sizeof *sieve * length * width) vs. malloc(length * width * sizeof *sieve) la seconde peut dépasser le length * width lorsque width et length sont des types plus petits que size_t.

2105
unwind

En C, vous n'avez pas besoin de convertir la valeur de retour de malloc. Le pointeur sur void renvoyé par malloc est automatiquement converti dans le type correct. Toutefois, si vous souhaitez que votre code soit compilé avec un compilateur C++, une conversion est nécessaire. Une alternative préférée parmi la communauté est d'utiliser les éléments suivants:

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

ce qui vous évite en outre de vous inquiéter de changer le côté droit de l'expression si vous changez le type de sieve.

Les lancers sont mauvais, comme les gens l'ont souligné. Spécialement lance des pointeurs.

354
dirkgently

Vous faites vous lancez, car:

  • Cela rend votre code plus portable entre C et C++, et comme le montre l’expérience SO, de nombreux programmeurs affirment qu’ils écrivent C quand ils écrivent vraiment en C++ (ou C plus des extensions de compilateur local).
  • Ne pas le faire peut masquer une erreur : notez tous les SO exemples de confusion au moment d'écrire type * par rapport à type **.
  • L'idée qu'elle vous empêche de remarquer que vous avez échoué à #include un fichier d'en-tête approprié manque à la forêt d'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 satané stdlib.h est la VRAIE chose importante à retenir!"
  • Cela force un recoupement cognitif supplémentaire . Cela place le type souhaité (présumé) 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 bogues malloc() sont détectés beaucoup plus rapidement lorsqu'il y a un casting. Comme pour les assertions, les annotations qui révèlent une intention réduisent les bogues.
  • Répéter vous-même d'une manière que la machine peut vérifier est souvent une bonne idée . En fait, c’est ce qu’est une assertion et cette utilisation de la fonte est une assertion. Les assertions restent la technique la plus générale pour obtenir le code correct, depuis que Turing a eu l’idée il ya tant d’années.
329
Ron Burk

Comme indiqué par d’autres, il n’est pas nécessaire pour C, mais pour C++. Si vous pensez compiler votre code C avec un compilateur C++, pour quelle raison que ce soit, vous pouvez utiliser une macro à la place, par exemple:

#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++.

162
quinmars

De la Wikipedia :

Avantages de la coulée

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

  • La distribution autorise les versions antérieures à 1989 de malloc ayant à l'origine renvoyé un caractère *.

  • Casting peut aider le développeur à identifier les incohérences dans le dimensionnement des types 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 de ce comportement sans requérir le transfert).

Inconvénients du casting

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

  • L'ajout de la distribution peut masquer l'échec d'inclure 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 transtypage, un avertissement est émis lorsque cet entier est affecté au pointeur. Cependant, avec le casting, cet avertissement n'est pas produit, masquant un bogue. Sur certaines architectures et certains modèles de données (tels que LP64 sur les systèmes 64 bits, où longs et les pointeurs sont 64 bits et int est 32 bits), cette erreur peut entraîner un comportement indéfini, car le malloc déclaré implicitement renvoie un message 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 structure de la mémoire, cela peut entraîner le bris de la pile. Ce problème est moins susceptible de passer inaperçu dans les compilateurs modernes, car ils produisent uniformément des avertissements indiquant qu'une fonction non déclarée a été utilisée. Par conséquent, un avertissement apparaîtra. Par exemple, le comportement par défaut de GCC consiste à afficher un avertissement indiquant "déclaration implicite incompatible de la fonction intégrée", que la conversion soit présente 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 converti.

Bien que malloc sans casting soit la méthode préférée et que la plupart des programmeurs expérimentés le choisissent , vous devez utiliser celui qui vous convient le mieux.

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 la transtypage.

125
ashiquzzaman33

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

100
PaulJWilliams

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

La raison la plus courante pour laquelle les utilisateurs affichent le résultat de malloc est qu'ils ne savent pas comment fonctionne le langage C. C'est un signe d'avertissement: si vous ne savez pas comment fonctionne un mécanisme de langage particulier, alors ne le faites pas . Cherchez ou demandez sur Stack Overflow.

Certains commentaires:

  • Un pointeur vide 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 toutefois pas une conversion implicite entre void* et un autre type de pointeur. Donc, en C++, le casting aurait été correct. Mais si vous programmez en C++, vous devez utiliser new et non 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 de placer 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 datant de plus de 25 ans, oublier d'inclure <stdlib.h> entraînerait un comportement dangereux. Parce que dans cet ancien standard, les fonctions sans prototype visible convertissaient implicitement le type de retour en int. Lancer explicitement le résultat de malloc cacherait alors ce bogue.

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

92
Lundin

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

86
EFraim

La conversion de la valeur renvoyée par malloc() n'est pas nécessaire à présent, mais j'aimerais ajouter un point qui semble ne pas avoir été signalé:

Dans les temps anciens, c’est-à-dire qu'avant , ANSI C fournit le void * en tant que type générique de pointeurs, char * est le tapez pour un tel usage. Dans ce cas, la distribution peut arrêter les avertissements du compilateur.

Référence: C FAQ

67
Yu Hao

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

50
user968000

En ajoutant simplement mon expérience, en étudiant en ingénierie informatique, je constate que les deux ou trois professeurs que j’ai vu écrire en C ont toujours jeté Malloc, mais celui que j’ai demandé (avec un immense CV et une compréhension de C) m’a dit que c’était absolument inutile, mais utilisé pour être absolument spécifique, et pour amener les étudiants dans la mentalité d’être absolument spécifique. Essentiellement, le casting ne changera rien à son fonctionnement, il fera exactement ce qu'il dit, allouera de la mémoire, et le casting ne le produira pas, vous obtiendrez la même mémoire, et même si vous le convertissez en un autre par erreur (et en évitant le 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 obtenu par transtypage. De cette façon, vous savez que pour un double, vous avez 8 octets de plus, tandis que pour un int, vous avez 4, et ainsi de suite. Ainsi, cela n'a aucun effet si vous utilisez la notation par pointeur, cela devient nécessaire en notation tableau.

49
user3079666

Voici ce que Le manuel GNU C Référence de la bibliothèque C dit:

Vous pouvez stocker le résultat de malloc dans toute variable de pointeur sans transtypage, car ISO C convertit automatiquement le type void * en un autre type de pointeur, si nécessaire. Mais le transtypage est nécessaire dans des contextes autres que les opérateurs d'affectation ou si vous souhaitez que votre code soit exécuté en C traditionnel.

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

Le pointeur renvoyé si l'allocation réussit est correctement aligné de sorte qu'il puisse être affecté à un pointeur sur tout type d'objet nécessitant un alignement fondamental, puis utilisé pour accéder à un tel objet ou à un tableau d'objets de ce type dans l'espace alloué (jusqu'au l'espace est explicitement désalloué)

31
Slothworks

Un pointeur vide est un pointeur générique et C prend en charge la conversion implicite d'un type de pointeur vide à d'autres types. Il n'est donc pas nécessaire de le transtyper explicitement.

Toutefois, si vous souhaitez que le même code fonctionne parfaitement sur une plate-forme C++, qui ne prend pas en charge la conversion implicite, vous devez procéder à la conversion de type. Tout dépend donc de la convivialité.

30
Endeavour

Le type renvoyé est void *, qui peut être converti dans le type de pointeur de données souhaité pour pouvoir être déréférencé.

29
swaps

En langage C, un pointeur vide peut être affecté à n’importe quel pointeur. Par conséquent, vous ne devez pas utiliser de transtypage. Si vous voulez 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 fonction indispensable est

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

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

int i, a[100];

for (i = 0; i < LEN(a); i++) {
   ...
}
27
August Karlstrom

Cela dépend du langage de programmation et du compilateur. Si vous utilisez malloc en C, il n'est pas nécessaire de la transtyper, car elle sera automatiquement transtypée. Toutefois, si vous utilisez C++, vous devez taper cast car malloc renverra un void* type.

26
Jeyamaran

Les gens habitués à GCC et Clang sont gâtés. Ce n'est pas si bon que ça.

Au fil des ans, j'ai été assez horrifié par les compilateurs incroyablement âgés que je devais utiliser. Souvent, les entreprises et les gestionnaires adoptent une approche ultra-conservatrice pour changer de compilateur et ne vont même pas tester si un nouveau compilateur (avec une meilleure conformité aux normes et 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 that devrait être la méthode que les gens suivent si elle est définie. En l'absence de directives explicites, j'ai tendance à privilégier les compilations les plus susceptibles d'être compilées partout, plutôt que l'adhésion scrupuleuse à 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 le niveau actuel, mais par les aspects pratiques de ce que j'aime appeler "le champ de réalité du management local". Et c'est plus tordu que l'espace-temps n'a jamais été. :-)

YMMV.

J'ai tendance à penser que le casting de malloc est une opération défensive. Pas joli, pas parfait, mais généralement sans danger. (Honnêtement, si vous n’avez pas inclus stdlib.h, alors vous avez chemin plus de problèmes que le casting de malloc!).

16
StephenG

Je mets dans le casting simplement pour montrer la désapprobation du vilain trou dans le système de types, ce qui permet à un code tel que l'extrait suivant de se compiler sans diagnostics, 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 je lance donc. Cela représente mon goût et ma politique de programmation. Je ne lance pas seulement un pointeur, mais effectivement, je vote, et chassant les démons stupides . Si je ne peux pas réellement jeter la stupidité , laissez-moi au moins exprimer le souhait de le faire avec un geste de manifestation.

En fait, une bonne pratique consiste à envelopper malloc (et ses amis) avec des fonctions renvoyant unsigned char *, et à ne jamais 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 conversions dans les deux sens. La seule détente à laquelle vous pouvez vous adonner consiste peut-être à utiliser des fonctions telles que memset et memcpy sans transtypage.

En ce qui concerne le casting et la compatibilité C++, si vous écrivez votre code de telle sorte qu'il soit compilé en C et C++ (dans ce cas, vous devez convertir le renvoyer la valeur malloc lorsque vous l'assignez à autre chose que void *), vous pouvez effectuer une opération très utile pour vous-même: vous pouvez utiliser des macros pour la conversion qui se traduisent par des conversions de style C++ lors de la compilation en C++, mais réduire à 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 vous en tenez à ces macros, une simple recherche grep de votre base de code pour trouver ces identificateurs vous indiquera où se trouvent tous vos conversions. Vous pourrez ainsi vérifier si certains d'entre eux sont incorrects.

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

Pour vous aider à adhérer à ces macros, le compilateur GNU C++ (pas C!) A une belle fonctionnalité: un diagnostic facultatif produit pour toutes les occurrences de transtypages de style C.

 -Wold-style-cast (C++ et Objective-C++ uniquement) 
 Avertir si un casting de style ancien (style C) vers un type non vide est utilisé 
 Dans les conditions suivantes: un programme C++. Les conversions de style nouveau (dynamic_cast, 
 Static_cast, reinterpret_cast et const_cast) sont moins vulnérables 
 Aux effets inattendus et beaucoup plus faciles à rechercher. 

Si votre code C est compilé en C++, vous pouvez utiliser cette option -Wold-style-cast pour connaître toutes les occurrences de la syntaxe de conversion (type) susceptible de s’insérer dans le code, et effectuer un suivi de ces diagnostics en les remplaçant par un choix approprié parmi les macros ci-dessus (ou une combinaison, si nécessaire).

Ce traitement des conversions est la plus grande justification technique autonome permettant de travailler dans un "Clean C": les dialectes combinés C et C++, ce qui justifie techniquement la conversion de la valeur de retour de malloc.

14
Kaz

Je préfère faire le casting, mais pas manuellement. Mon favori utilise les macros g_new et g_new0 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é du type. Si vous vous trompez de type, vous obtenez une conversion implicite entre des pointeurs non vides, ce qui provoque un avertissement (erreur en C++). Si vous oubliez d'inclure l'en-tête qui définit g_new et g_new0, vous obtiendrez une erreur. g_new et g_new0 prennent tous deux les mêmes arguments, contrairement à malloc qui prend moins d'arguments que calloc. Ajoutez simplement 0 pour obtenir une mémoire initialisée à zéro. Le code peut être compilé avec un compilateur C++ sans modifications.

13
proski

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

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

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

Mais il y a une raison beaucoup plus forte pour ne pas introduire de fontes de pointeur inutiles:

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

La valeur stockée d'un objet doit être accessible uniquement par une expression lvalue qui possède 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 inclut l'un des types susmentionnés parmi ses membres (y compris, de manière récursive, un membre d'un syndicat sous-agrégé ou confiné), ou
- un type de caractère.

Cette règle est également appelée règle de crénelage strict . Le code suivant est donc un comportement non défini :

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

Et, ce qui est parfois surprenant, voici ce qui suit:

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 do avez besoin de lancer des pointeurs, mais étant donné la règle de crénelage stricte , vous devez faire très attention à cela. Ainsi, toute occurrence d’un pointeur dans votre code est un endroit où vous vous devez vérifier sa validité. Par conséquent, vous n'écrivez jamais une distribution de pointeur inutile.

tl; dr

En un mot: Parce qu'en C, toute l'occurrence d'un pointeur converti devrait déclencher un drapeau rouge pour le code requérant une attention particulière, vous ne devriez jamais écrire inutile le pointeur est projeté.


Notes de côté:

  • Il existe des cas où vous avez réellement besoin d'une conversion vers void *, par exemple. si vous voulez imprimer un pointeur:

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

    La conversion est nécessaire ici, car printf() est une fonction variadique, les conversions implicites ne fonctionnent donc pas.

  • En C++, la situation est différente. La diffusion de types de pointeurs est quelque peu commune (et correcte) 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 void * soit non implicite. C++ a tout un ensemble de différentes saveurs de casting.

13
user2371524

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

  1. Compilez votre programme avec un compilateur C avec tous les avertissements activés -Wall et corrigez toutes les erreurs et tous les avertissements
  2. Assurez-vous qu'il n'y a pas de variables déclarées comme auto
  3. Puis compilez-le à l'aide d'un compilateur C++ avec -Wall et -std=c++11. Corrigez toutes les erreurs et tous les avertissements.
  4. Maintenant, compilez à nouveau avec le compilateur C. Votre programme devrait maintenant compiler sans avertissement et contenir moins de bugs.

Cette procédure vous permet de tirer parti 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 cette étendue

et vous oblige également à jeter le résultat de malloc ou vous obtiendrez

conversion invalide 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, runtime polymorphism]

Notez que le second inconvénient devrait dans l'idéal disparaître lors de l'utilisation du sous-ensemble commun à C avec la fonctionnalité 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...
13
user877329

Le casting ne concerne que le C++ et non le C. Si vous utilisez un compilateur C++, il vaut mieux le changer en compilateur C.

11
user3949394

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

10
iec2011007

Un pointeur vide est un pointeur générique et C prend en charge la conversion implicite d'un type de pointeur vide à d'autres types. Il n'est donc pas nécessaire de le transtyper explicitement.

Toutefois, si vous souhaitez que le même code fonctionne parfaitement sur une plate-forme C++, qui ne prend pas en charge la conversion implicite, vous devez procéder à la conversion de type. Tout dépend donc de la convivialité.

8
dhana govindarajan
  1. Comme indiqué par d’autres, il n’est pas nécessaire pour C, mais pour C++.

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

  3. En C, cela n’est pas nécessaire, car void * est automatiquement et sûrement promu en un autre type de pointeur.

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

    Parce que stdlib.h contient le prototype pour 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 transtypage, un avertissement est émis lorsque cet entier est affecté au pointeur. Cependant, avec le casting, cet avertissement n'est pas produit, masquant un bogue.

8
Mohit

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

Le casting est inutile en C à cause de:

  • void * est automatiquement et en toute sécurité promu en tout autre type de pointeur dans le cas de C.
  • Cela peut cacher une erreur si vous avez oublié d'inclure <stdlib.h>. Cela peut provoquer des accidents.
  • Si les pointeurs et les entiers sont de tailles différentes, vous masquez un avertissement en diffusant et risquez de perdre des bits de votre adresse renvoyée.
  • 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 converti.

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

5
Aashish