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

Dans cette question , quelqu’un a suggéré dans un commentaire que je ne devais pas lancer le résultat de malloc , c.-à-d.

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

plutôt que:

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

Pourquoi serait-ce le cas?

Non vous ne lancez pas le résultat, puisque:

  • Il est inutile, car void * est promu automatiquement et en toute sécurité dans tout autre type de pointeur dans ce cas.
  • Cela ajoute du désordre au code, les fontes ne sont pas très faciles à lire (surtout si le type de pointeur est long).
  • Cela vous fait répéter, ce qui est généralement mauvais.
  • Il peut cacher une erreur si vous avez oublié d’inclure . Cela peut causer des pannes (ou, pire, ne pas causer de plantage jusqu’à une date ultérieure 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 coulant et risquez de perdre des morceaux de votre adresse de retour. Note: à partir de C11, 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 renvoient à 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 à inclure les acteurs, même si vous avez bien compris. Il n’y a tout simplement aucun avantage à le faire, mais un tas de risques potentiels, et l’inclusion de la dissortingbution indique que vous ne connaissez pas les risques.

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

Pour append plus loin, 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, pour “verrouiller” les deux ensemble:

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

Cela déplace également la 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! 🙂


Bien que le déplacement de la length vers l’avant puisse augmenter la visibilité dans de rares cas, il convient également de noter que, dans le cas général, il serait préférable d’écrire l’expression comme suit:

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

Depuis la conservation de la sizeof premier, dans ce cas, la multiplication est effectuée avec au moins size_t math.

Compare: malloc(sizeof *sieve * length * width) vs. malloc(length * width * sizeof *sieve) le second peut déborder de length * width lorsque width et length sont plus petits que size_t .

En C, vous n’avez pas besoin de lancer la valeur de retour de malloc . Le pointeur à annuler renvoyé par malloc est automatiquement converti au type correct. Cependant, si vous voulez que votre code comstack avec un compilateur C ++, une dissortingbution 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 devoir vous soucier de changer le côté droit de l’expression si vous changez le type de sieve .

Les moulages sont mauvais, comme les gens l’ont fait remarquer. Spécialement lancé par un pointeur.

Vous lancez parce que:

  • Cela rend votre code plus portable entre C et C ++, et comme le montre l’expérience de SO, de nombreux programmeurs affirment qu’ils écrivent en C alors qu’ils écrivent vraiment en C ++ (ou C plus les extensions locales du compilateur).
  • Ne pas le faire peut masquer une erreur : notez tous les exemples SO de confusion au moment d’écrire le type * versus le type ** .
  • L’idée que cela vous empêche de remarquer que vous n’avez pas réussi à #include un fichier d’en-tête approprié manque la forêt pour les arbres . C’est la même chose que de dire “ne vous inquiétez pas du fait que vous n’avez pas demandé au compilateur de se plaindre de ne pas voir de prototypes – ce stdlib.h est la chose la plus importante à retenir!”
  • Il force une vérification croisée cognitive supplémentaire . Il place le type désiré (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 de malloc() sont capturés beaucoup plus rapidement quand il y a une dissortingbution. Comme pour les assertions, les annotations qui révèlent l’intention diminuent les bogues.
  • Se répéter d’une manière que la machine peut vérifier est souvent une bonne idée. En fait, c’est ce qu’une assertion est, et cette utilisation de cast est une assertion. Les assertions restnt la technique la plus générale pour corriger le code, puisque Turing a eu cette idée il y a de nombreuses années.

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

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

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

 int *sieve = NEW(int, 1); 

et il comstackra pour C et C ++.

De Wikipedia

Avantages de la casting

  • Inclure la dissortingbution peut permettre à un programme C ou à une fonction de se comstackr en C ++.

  • La dissortingbution autorise les versions antérieures à 1989 de malloc qui renvoyaient à l’origine un caractère *.

  • Le casting peut aider le développeur à identifier les incohérences dans le dimensionnement de 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 parsingurs statiques

Inconvénients de la casting

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

  • L’ajout de la dissortingbution peut masquer l’incapacité d’inclure l’en-tête stdlib.h , dans lequel le prototype de malloc est trouvé. En l’absence d’un prototype pour malloc, le standard exige que le compilateur C suppose que malloc renvoie un int. S’il n’y a pas de dissortingbution, 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 certains modèles de données (tels que LP64 sur les systèmes 64 bits, où long et les pointeurs sont 64 bits et int 32 bits), cette erreur peut entraîner un comportement indéfini, car la déclaration implicite de malloc 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 disposition de la mémoire, cela peut entraîner un bris de stack. Ce problème est moins susceptible de passer inaperçu dans les compilateurs modernes, car ils génèrent des avertissements uniformes indiquant qu’une fonction non déclarée a été utilisée. Un avertissement apparaîtra toujours. 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 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 sur lesquelles malloc est appelé et converti.

Bien que malloc sans casting soit la méthode privilégiée et que la plupart des programmeurs expérimentés le choisissent , vous devez utiliser ce que vous souhaitez en avoir connaissance.

ie: Si vous avez besoin de comstackr le programme C en C ++ (bien que ce soit un langage séparé), vous devriez utiliser malloc avec casting.

En C, vous pouvez implicitement convertir un pointeur vide en un autre type de pointeur, de sorte qu’une dissortingbution n’est pas nécessaire. En utilisant l’un peut suggérer à l’observateur occasionnel qu’il y a une raison pour laquelle il en faut une, ce qui peut être trompeur.

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

La raison la plus courante pour laquelle les gens jettent le résultat de malloc est 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 le devinez pas. Recherchez-le ou posez-vous sur Stack Overflow.

Certains commentaires:

  • Un pointeur vide peut être converti en / depuis tout autre type de pointeur sans conversion explicite (C11 6.3.2.3 et 6.5.16.1).

  • C ++ ne permettra 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 devriez utiliser new et non malloc (). Et vous ne devriez jamais comstackr le 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 du compilateur pour marquer les différences. N’essayez pas de classer les deux normes de langue avec le même code, car elles ne sont pas compatibles.

  • Si un compilateur C ne trouve pas de 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 ce n’est pas grave, vous ne pourrez pas créer votre programme.

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

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

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

Il n’est pas nécessaire de lancer la valeur renvoyée par malloc() , mais j’aimerais append un point qui semble ne pas avoir été signalé:

Dans les temps anciens, c’est-à-dire avant que l’ ANSI C fournisse le void * comme type de pointeur générique, char * est le type de cet usage. Dans ce cas, la dissortingbution peut arrêter les avertissements du compilateur.

Référence: C FAQ

Il n’est pas obligatoire de lancer les résultats de malloc , car il renvoie void* , et un void* peut être dirigé vers n’importe quel type de données.

En ajoutant mon expérience, en étudiant l’ingénierie informatique, je vois que les deux ou trois professeurs que j’ai vu écrire en C jettent toujours malloc, mais celui que j’ai demandé (avec un immense CV et une compréhension de C) m’a dit que J’avais l’habitude d’ê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 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 transformez par erreur 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 connaître le nombre d’espaces de mémoire qu’il doit avancer pour atteindre le début de l’élément suivant, grâce à 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 de pointeur, en notation, cela devient nécessaire.

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

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

Cependant, si vous voulez que le même code fonctionne parfaitement sur une plateforme C ++, qui ne supporte pas la conversion implicite, vous devez procéder à la conversion, donc tout dépend de la facilité d’utilisation.

Ajouter à toutes les informations ici; c’est ce que dit le manuel de référence de la bibliothèque GNU C :

Vous pouvez stocker le résultat de malloc dans n’importe quelle variable de pointeur sans fonte, car ISO C convertit automatiquement le type void * en un autre type de pointeur si nécessaire. Mais la dissortingbution 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 traditionnel.

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

Le pointeur est retourné si l’atsortingbution réussit est correctement alignée de sorte qu’il puisse être assigné à un pointeur sur n’importe quel type d’object avec une exigence d’alignement fondamental et utilisé ensuite pour accéder à un tel object ou à un tableau de ces objects dans l’espace alloué l’espace est explicitement désalloué)

Cela dépend du langage de programmation et du compilateur. Si vous utilisez malloc en C, il n’est pas nécessaire de taper cast, car il saisira automatiquement Cast, cependant si vous utilisez C ++, vous devez taper cast car malloc renverra un type void* .

En langage C, un pointeur vide peut être assigné à n’importe quel pointeur, ce qui explique pourquoi vous ne devez pas utiliser de type cast. Si vous voulez une allocation “type safe”, je peux recommander les fonctions de macro suivantes, que j’utilise toujours dans mes projets C:

 #include  #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 dynamics, 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++) { ... } 

Casting est uniquement pour C ++, pas pour C. Si vous utilisez un compilateur C ++, il vaut mieux le changer en compilateur C.

Les personnes habituées à GCC et à Clang sont gâtées. Ce n’est pas si bon que ça.

J’ai été assez horrifié au fil des ans par les compilateurs énormément âgés que j’ai dû utiliser. Souvent, les entresockets et les gestionnaires adoptent une approche ultra-conservasortingce pour changer les compilateurs 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 mallocs est une bonne habitude si vous ne pouvez pas contrôler quel compilateur peut être appliqué à votre code.

Je voudrais également suggérer que de nombreuses organisations appliquent une norme de codage qui leur soit propre et que cela devrait être la méthode que les gens suivent si elle est définie. En l’absence de directives explicites, j’ai tendance à choisir les plus susceptibles de comstackr partout, plutôt que d’adhérer à 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 domaine de la réalité de la gestion locale». Et cela est plié et tordu plus que l’espace-temps. 🙂

YMMV.

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

Je mets la dissortingbution simplement pour montrer la désapprobation du trou moche dans le système de type, ce qui permet au code tel que l’extrait suivant de comstackr sans diagnostic, même si aucune conversion n’est utilisée 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 en C ++) et donc je lance. Cela représente mon goût et ma politique de programmation. Je ne suis pas seulement en train de lancer un point, mais bien de voter, et de chasser les démons de la stupidité . Si je ne peux pas réellement rejeter la stupidité , alors au moins laissez-moi 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 renvoient des caractères unsigned char * , et en principe ne jamais utiliser void * dans votre code. Si vous avez besoin d’un pointeur-à-n’importe-object générique, utilisez un caractère char * ou unsigned char * , et lancez-le dans les deux sens. La relaxation que l’on peut se permettre, peut-être, consiste à utiliser des fonctions telles que memset et memcpy sans memcpy .

On the topic of casting and C++ compatibility, if you write your code so that it comstacks as both C and C++ (in which case you have to cast the return value of malloc when assigning it to something other than void * ), you can do a very helpful thing for yourself: you can use macros for casting which translate to C++ style casts when compiling as C++, but reduce to a C cast when compiling as C:

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

If you adhere to these macros, then a simple grep search of your code base for these identifiers will show you where all your casts are, so you can review whether any of them are incorrect.

Then, going forward, if you regularly comstack the code with C++, it will enforce the use of an appropriate cast. For instance, if you use ssortingp_qual just to remove a const or volatile , but the program changes in such a way that a type conversion is now involved, you will get a diagnostic, and you will have to use a combination of casts to get the desired conversion.

To help you adhere to these macros, the the GNU C++ (not C!) comstackr has a beautiful feature: an optional diagnostic which is produced for all occurrences of C style casts.

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

If your C code comstacks as C++, you can use this -Wold-style-cast option to find out all occurrences of the (type) casting syntax that may creep into the code, and follow up on these diagnostics by replacing it with an appropriate choice from among the above macros (or a combination, if necessary).

This treatment of conversions is the single largest standalone technical justification for working in a “Clean C”: the combined C and C++ dialect, which in turn technically justifies casting the return value of malloc .

The concept behind void pointer is that it can be casted to any data type that is why malloc returns void. Also you must be aware of automatic typecasting. So it is not mandatory to cast the pointer though you must do it. It helps in keeping the code clean and helps debugging

The best thing to do when programming in C whenever it is possible:

  1. Make your program comstack through a C comstackr with all warnings turned on -Wall and fix all errors and warnings
  2. Make sure there are no variables declared as auto
  3. Then comstack it using a C++ comstackr with -Wall and -std=c++11 . Fix all errors and warnings.
  4. Now comstack using the C comstackr again. Your program should now comstack without any warning and contain fewer bugs.

This procedure lets you take advantage of C++ ssortingct type checking, thus reducing the number of bugs. In particular, this procedure forces you to include stdlib.h or you will get

malloc was not declared within this scope

and also forces you to cast the result of malloc or you will get

invalid conversion from void* to T*

or what ever your target type is.

The only benefits from writing in C instead of C++ I can find are

  1. C has a well specified ABI
  2. C++ may generate more code [exceptions, RTTI, templates, runtime polymorphism]

Notice that the second cons should in the ideal case disappear when using the subset common to C together with the static polymorphic feature.

For those that finds C++ ssortingct rules inconvenient, we can use the C++11 feature with inferred type

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

No, you don’t cast the result of malloc() .

In general, you don’t cast to or from void * .

A typical reason given for not doing so is that failure to #include could go unnoticed. This isn’t an issue anymore for a long time now as C99 made implicit function declarations illegal, so if your comstackr conforms to at least C99, you will get a diagnostic message.

But there’s a much stronger reason not to introduce unnecessary pointer casts:

In C, a pointer cast is almost always an error . This is because of the following rule ( §6.5 p7 in N1570, the latest draft for C11):

An object shall have its stored value accessed only by an lvalue expression that has one of the following types:
— a type compatible with the effective type of the object,
— a qualified version of a type compatible with the effective type of the object,
— a type that is the signed or unsigned type corresponding to the effective type of the object,
— a type that is the signed or unsigned type corresponding to a qualified version of the effective type of the object,
— an aggregate or union type that includes one of the aforementioned types among its members (including, recursively, a member of a subaggregate or contained union), or
— a character type.

This is also known as the ssortingct aliasing rule . So the following code is undefined behavior :

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

And, sometimes surprisingly, the following is as well:

 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; 

Sometimes, you do need to cast pointers, but given the ssortingct aliasing rule , you have to be very careful with it. So, any occurrence of a pointer cast in your code is a place you have to double-check for its validity . Therefore, you never write an unnecessary pointer cast.

tl;dr

In a nutshell: Because in C, any occurrence of a pointer cast should raise a red flag for code requiring special attention, you should never write unnecessary pointer casts.


Notes annexes:

  • There are cases where you actually need a cast to void * , eg if you want to print a pointer:

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

    The cast is necessary here, because printf() is a variadic function, so implicit conversions don’t work.

  • In C++, the situation is different. Casting pointer types is somewhat common (and correct) when dealing with objects of derived classes. Therefore, it makes sense that in C++, the conversion to and from void * is not implicit. C++ has a whole set of different flavors of casting.

I prefer to do the cast, but not manually. My favorite is using g_new and g_new0 macros from glib. If glib is not used, I would add similar macros. Those macros reduce code duplication without compromising type safety. If you get the type wrong, you would get an implicit cast between non-void pointers, which would cause a warning (error in C++). If you forget to include the header that defines g_new and g_new0 , you would get an error. g_new and g_new0 both take the same arguments, unlike malloc that takes fewer arguments than calloc . Just add 0 to get zero-initialized memory. The code can be comstackd with a C++ comstackr without changes.

A void pointer is a generic pointer and C supports implicit conversion from a void pointer type to other types, so there is no need of explicitly typecasting it.

However, if you want the same code work perfectly compatible on a C++ platform, which does not support implicit conversion, you need to do the typecasting, so it all depends on usability.

  1. As other stated, it is not needed for C, but for C++.

  2. Including the cast may allow a C program or function to comstack as C++.

  3. In C it is unnecessary, as void * is automatically and safely promoted to any other pointer type.

  4. But if you cast then, it can hide an error if you forgot to include stdlib.h . This can cause crashes (or, worse, not cause a crash until way later in some totally different part of the code).

    Because stdlib.h contains the prototype for malloc is found. In the absence of a prototype for malloc, the standard requires that the C comstackr assumes malloc returns an int. If there is no cast, a warning is issued when this integer is assigned to the pointer; however, with the cast, this warning is not produced, hiding a bug.

The casting of malloc is unnecessary in C but mandatory in C++.

  • Casting is unnecessary in C because of void * is automatically and safely promoted to any other pointer type in this case.
  • It can hide an error if you forgot to include . This can cause crashes.
  • If pointers and integers are differently sized, then you’re hiding a warning by casting and might lose bits of your returned address.

Please do yourself a favor and more importantly a favor for the next person who will maintain your code, and provide as much information as possible about the data type of a program’s variables.

Thus, cast the returned pointer from malloc . In the following code the comstackr can be assured that sieve is in fact being assigned a point to an integer(s).

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

This reduces the chance for a human error when/if the data type for sieve is changed.

I would be interestd in knowing if there are any “pure” C comstackrs that would flag this statement as being in error. If so, let me know, so that I can avoid them as their lack of type checking will increase the overall expense of maintaining software.