Question

Dans cette question , quelqu'un suggéré dans un commenter que je ne doit pas diffuser 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?

Était-ce utile?

La solution

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

  • Cela n'est pas nécessaire, car void * est automatiquement et en toute sécurité promu en un autre type de pointeur dans ce cas.
  • Cela ajoute de l'encombrement au code, les conversions ne sont pas très faciles à lire (surtout si le type de pointeur est long).
  • Cela vous oblige à 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, ne pas 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 car il n’existe aucune hypothèse automatique selon laquelle les fonctions non déclarées renvoient int.

À titre de précision, 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 simplement aucun avantage, mais de nombreux 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 davantage, votre code répète inutilement les informations de type (length) qui peuvent 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);

Ceci déplace également le sizeof devant pour une visibilité accrue, et supprime les parenthèses redondantes avec size_t; 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: malloc(sizeof *sieve * length * width) n’est pas une fonction! :)

Bien que le passage malloc(length * width * sizeof *sieve) au début puisse augmenter la visibilité dans certains cas rares, il convient également de noter que, dans le cas général, il est préférable d'écrire l'expression sous la forme suivante:

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

Puisque garder le length * width premier, dans ce cas, assure que la multiplication est faite avec au moins width maths.

Comparez: <=> vs <=> le second risque de déborder du <=> lorsque <=> et <=> sont des types plus petits que <=>.

Autres conseils

En C, vous n'avez pas besoin de convertir la valeur de retour de malloc. Le pointeur à annuler renvoyé par sieve 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 privilégiée par la communauté consiste à utiliser les éléments suivants:

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

ce qui vous évite également de vous inquiéter de changer le côté droit de l'expression si vous changez le type de <=>.

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

Vous diffusez , car:

  • Cela rend votre code plus portable entre le C et le C ++ et, comme le montre l'expérience de SO, de nombreux programmeurs affirment qu'ils écrivent en C alors qu'ils écrivent réellement en C ++ (ou un compilateur local C plus extensions).
  • Si vous ne le faites pas, peut masquer une erreur : notez tous les exemples SO de confusion qui vous empêchent d'écrire type * par rapport à type **.
  • L'idée selon laquelle cela vous empêche de remarquer que vous avez échoué à #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’ayez pas demandé au compilateur de se plaindre de ne pas voir les prototypes - ce satané stdlib.h est la vraie chose importante à retenir! &"; / li>
  • Cela force une vérification croisée cognitive 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 malloc() les bugs sont attrapés beaucoup plus rapidement quand il y a un casting. Comme pour les assertions, les annotations qui révèlent une intention réduisent les bogues.
  • Se répéter pour que la machine puisse 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 dont nous disposons pour obtenir le code correct, depuis que Turing a eu l’idée il ya tant d'années.

Comme indiqué précédemment, 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

Ainsi, vous pourrez toujours l'écrire de manière très compacte:

int *sieve = NEW(int, 1);

et il compilera pour C et C ++.

De la Wikipedia :

  

Avantages de la diffusion

     
      
  • L'inclusion de la conversion peut permettre à un programme ou une fonction C de se 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 du type si le type du 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 le casting).

  •   
     

Inconvénients de la diffusion

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

  •   
  • L'ajout de la distribution peut masquer l'incapacité d'inclure l'en-tête stdlib.h , dans   où se trouve le prototype de malloc. En l'absence d'un   prototype pour malloc, la norme exige que le compilateur C   supposer que malloc retourne un int. S'il n'y a pas de casting, 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 certains   architectures et modèles de données (tels que LP64 sur des systèmes 64 bits, où   long et les pointeurs sont 64 bits et int est 32 bits), cette erreur peut   entraîner un comportement indéfini, comme l'a implicitement déclaré   malloc renvoie une valeur 32 bits alors que la fonction réellement définie   renvoie une valeur de 64 bits. En fonction des conventions d'appel et de la mémoire   mise en page, cela peut entraîner un éclatement 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, donc un avertissement sera   apparaissent toujours. Par exemple, le comportement par défaut de GCC est d’afficher un   avertissement qui lit & "; déclaration implicite incompatible de la fonction intégrée   fonction " que la distribution soit présente ou non.

  •   
  • Si le type du pointeur est modifié lors de sa déclaration, on peut   de plus, il faut changer toutes les lignes où malloc est appelé et jeté.

  •   

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 devez compiler le programme C en C ++ (bien que ces langues soient séparées), vous devez utiliser malloc avec la conversion.

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.

Vous ne diffusez 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 linguistique particulier, alors ne ne tentez pas de deviner. Cherchez-le ou posez des questions sur le dépassement de pile.

Quelques 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 avec 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. Ne tentez pas de définir 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 oubliez 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 int entraînerait un comportement dangereux. Parce que dans cet ancien standard, les fonctions sans prototype visible convertissaient implicitement le type de retour en <=>. 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?

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

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

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

Référence: FAQ sur le langage C

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

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 seulement 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 jetez par inadvertance (et que vous évitiez 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 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.

C’est ce que Référence de la bibliothèque GNU C le manuel dit:

  

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

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

  

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

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 convertir 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é.

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

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 & "; Tapez safe &"; allocation, je peux 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 tableaux plus sûres et plus pratiques:

int i, a[100];

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

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

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

J'ai été assez horrifié au fil des ans par les compilateurs extrêmement âgés que je devais utiliser. Les entreprises et les gestionnaires adoptent souvent une approche ultra-conservatrice pour changer de compilateur et ne vont même pas tester si un nouveau compilateur (offrant 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 le compilateur qui peut être appliqué à votre code.

Je suggérerais également que de nombreuses organisations appliquent leur propre norme de codage et que 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 la compilation la plus probable, plutôt que l’adhésion esclave à 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 standard du jour, mais par les aspects pratiques de ce que j'aime appeler & "Le champ de réalité de la gestion locale &". 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, vous avez moyen plus de problèmes que de lancer malloc!).

Je mets simplement dans la distribution simplement pour montrer la désapprobation du vilain trou dans le système de types, ce qui permet au code tel que l'extrait suivant de se compiler sans diagnostics, même si aucun transfert n'est utilisé pour provoquer la mauvaise conversion:

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

Je souhaite que cela n’existe pas (et ce n’est pas le cas en C ++) et j’ai donc lancé le casting. Cela représente mon goût et ma politique de programmation. Je ne lance pas seulement un pointeur, mais aussi un bulletin de vote et chassant les démons de la stupidité . Si je ne peux pas réellement rejeter la stupidité , permettez-moi au moins d'exprimer les souhaite le faire avec un geste de protestation.

En fait, une bonne pratique consiste à encapsuler malloc (et ses amis) avec des fonctions renvoyées unsigned char * et, en principe, à 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 memset, et effectuez des conversions dans les deux sens. La seule détente qui peut être offerte consiste peut-être à utiliser des fonctions telles que memcpy et grep sans conversions.

Sur le thème de la conversion et de 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 la valeur de retour de strip_qual lors de l'attribution). à autre chose que const), vous pouvez faire une chose très utile pour vous-même: vous pouvez utiliser des macros de transtypage traduites en style C ++ lors de la compilation en C ++, mais réduites à 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 volatile recherche de ces identifiants dans la base de code vous montrera où se trouvent tous vos moulages. Vous pourrez ainsi vérifier si certains d'entre eux sont incorrects.

Ensuite, si vous compilez régulièrement le code avec C ++, cela imposera l'utilisation d'un transtypage approprié. Par exemple, si vous utilisez -Wold-style-cast seulement pour supprimer un (type) ou <=>, mais que le programme change de sorte qu'une conversion de type soit désormais impliquée, vous obtiendrez un diagnostic et vous devrez utiliser 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 qui est produit pour toutes les occurrences de transtypages de style C.

     -Wold-style-cast (C++ and Objective-C++ only)
         Warn if an old-style (C-style) cast to a non-void type is used
         within a C++ program.  The new-style casts (dynamic_cast,
         static_cast, reinterpret_cast, and const_cast) are less vulnerable
         to unintended effects and much easier to search for.

Si votre code C est compilé en tant que C ++, vous pouvez utiliser cette option <=> pour connaître toutes les occurrences de la syntaxe <=> de transtypage pouvant s’insérer dans le code, et effectuer un suivi de ces diagnostics en les remplaçant par un code approprié. choix 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 &: le dialecte combiné C et C ++, ce qui justifie techniquement la conversion de la valeur de retour <= >.

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. Ensuite, compilez-le à l'aide d'un compilateur C ++ avec -std=c++11 et stdlib.h. 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 malloc ou vous obtiendrez

  

void* n'a pas été déclaré dans cette étendue

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

  

conversion invalide de <=> à <=>

ou quel que soit votre type de cible.

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

  1. C a un ABI bien spécifié
  2. C ++ peut générer davantage de code [exceptions, RTTI, modèles, polymorphisme runtime ]

Notez que le second inconvénient devrait dans l’espèce idéalement 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 un type inféré

auto memblock=static_cast<T*>(malloc(n*sizeof(T))); //Mult may overflow...

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

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

Une raison typique pour ne pas le faire est que cet échec à #include <stdlib.h> pourrait passer inaperçu. Cela n’est plus un problème depuis longtemps, C99 ayant rendu les déclarations de fonction implicites illégales, donc si votre compilateur est conforme à au moins C99, vous recevrez un message de diagnostic.

Mais il existe une raison bien plus forte de ne pas introduire de transformations de pointeurs inutiles:

En C, une diffusion de pointeur est presque toujours une erreur . Cela est dû à la règle suivante ( & # 167; 6,5 p7 dans N1570, dernière version pour C11):

  

La valeur stockée d'un objet ne doit être accessible que par une expression lvalue possédant l'une des valeurs suivantes:   les types suivants:
  & # 8212; un type compatible avec le type effectif de l'objet,
  & # 8212; une version qualifiée d'un type compatible avec le type effectif de l'objet,
  & # 8212; un type qui est le type signé ou non signé correspondant au type effectif du   objet,
  & # 8212; un type qui est le type signé ou non signé correspondant à une version qualifiée du   type effectif de l'objet,
  & # 8212; un agrégat ou un type d'union qui comprend 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
  & # 8212; un type de caractère.

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

tl; dr

En résumé: dans C, toute occurrence d'un attributaire doit déclencher un drapeau rouge pour le code exigeant une attention particulière, vous ne devez jamais écrire inutile. le pointeur jette.

Notes annexes:

  • Dans certains cas, vous avez réellement besoin d'un transtypage vers printf(), par exemple. si vous voulez imprimer un pointeur:

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

    La conversion est nécessaire ici, car <=> étant une fonction variadique, les conversions implicites ne fonctionnent 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 <=> ne soit pas implicite. C ++ propose tout un éventail de variantes de casting.

Je préfère faire le casting, mais pas manuellement. Mon préféré utilise g_new et g_new0 les macros 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 le type est incorrect, 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 malloc et calloc, vous obtiendrez une erreur. 0 et <=> prennent les mêmes arguments, contrairement à <=> qui prend moins d'arguments que <=>. Ajoutez simplement <=> pour obtenir une mémoire initialisée à zéro. Le code peut être compilé avec un compilateur C ++ sans modifications.

La diffusion est réservée au C ++ et non au C. Si vous utilisez un compilateur C ++, il vaut mieux le changer en compilateur C.

Le concept du 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.

  1. Comme indiqué, cela 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 se compiler en C ++.

  3. En C, cela n’est pas nécessaire, car void * est automatiquement promu en toute sécurité vers tout 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 accidents (ou, pire, ne pas causer d'accident) jusqu’à plus tard dans une partie totalement différente du code).

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

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 convertir 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é.

La diffusion de malloc est inutile en C mais obligatoire en C ++.

La diffusion n'est pas nécessaire en C à cause de:

  • void * est automatiquement et en toute sécurité promu en un 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 votre annonce et risquez de perdre des bits.
  • 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 ++.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top