Maintenant, avant que les gens ne commencent à marquer cela comme un dup, j'ai lu tout ce qui suit, dont aucun ne fournit la réponse que je recherche:
- C FAQ: Quel est le problème avec la conversion de la valeur de retour de malloc?
- SO: Dois-je convertir explicitement la valeur de retour de malloc ()?
- SO: Inutile de lancer des pointeurs en C
- SO: Est-ce que je lance le résultat de malloc?
La FAQ C et de nombreuses réponses aux questions ci-dessus citent une erreur mystérieuse que malloc
la valeur de retour du casting peut masquer; cependant, aucun d'entre eux ne donne un exemple précis d'une telle erreur dans la pratique. Maintenant, faites attention que j'ai dit erreur , pas d' avertissement .
Maintenant donné le code suivant:
#include <string.h>
#include <stdio.h>
// #include <stdlib.h>
int main(int argc, char** argv) {
char * p = /*(char*)*/malloc(10);
strcpy(p, "hello");
printf("%s\n", p);
return 0;
}
Compiler le code ci-dessus avec gcc 4.2, avec et sans le cast donne les mêmes avertissements, et le programme s'exécute correctement et fournit les mêmes résultats dans les deux cas.
anon@anon:~/$ gcc -Wextra nostdlib_malloc.c -o nostdlib_malloc
nostdlib_malloc.c: In function ‘main’:
nostdlib_malloc.c:7: warning: incompatible implicit declaration of built-in function ‘malloc’
anon@anon:~/$ ./nostdlib_malloc
hello
Quelqu'un peut - il donner un exemple de code spécifique d 'une erreur de compilation ou d' exécution qui pourrait se produire en raison de malloc
la valeur de retour de la conversion, ou est - ce juste une légende urbaine?
Edit Je suis tombé sur deux arguments bien écrits concernant ce problème:
- En faveur de la diffusion: Avis CERT: convertir immédiatement le résultat d'un appel de fonction d'allocation de mémoire en un pointeur vers le type alloué
- Contre la diffusion (erreur 404 du 14/02/2012: utilisez la copie Internet Archive Wayback Machine du 27/01/2010. {18/03/2016: "La page ne peut pas être explorée ou affichée en raison du fichier robots.txt."})
void
pointeurs permet de compiler le code en C ++; certaines personnes disent que c'est une fonctionnalité, je dirais que c'est un bug;)malloc
la valeur de retour du transtypage: transtypageint*
sur un arch 64 bits.C
pas étiquetéeC++
(il s'agit de deux langues différentes). Toute discussion (comme dans certaines réponses) n'est donc pas pertinente pour cette question.Réponses:
Vous n'obtiendrez pas une erreur du compilateur , mais un avertissement du compilateur . Comme le disent les sources que vous citez (en particulier la première ), vous pouvez obtenir une erreur d'exécution imprévisible lors de l'utilisation de la distribution sans inclure
stdlib.h
.Donc l'erreur de votre côté n'est pas le casting, mais oublier d'inclure
stdlib.h
. Les compilateurs peuvent supposer qu'ilmalloc
s'agit d'une fonction retournantint
, convertissant ainsi levoid*
pointeur réellement retourné parmalloc
versint
, puis vers votre type de pointeur en raison de la conversion explicite. Sur certaines plates-formes, lesint
pointeurs peuvent prendre différents nombres d'octets, de sorte que les conversions de type peuvent entraîner une corruption des données.Heureusement, les compilateurs modernes donnent des avertissements qui indiquent votre erreur réelle. Voir le
gcc
résultat que vous avez fourni: il vous avertit que la déclaration implicite (int malloc(int)
) est incompatible avec le intégrémalloc
. Doncgcc
semble savoirmalloc
même sansstdlib.h
.Oublier le casting pour éviter cette erreur est généralement le même raisonnement que l'écriture
if (0 == my_var)
au lieu de
if (my_var == 0)
puisque ce dernier pourrait conduire à un bogue sérieux si l'on confondait
=
et==
, alors que le premier conduirait à une erreur de compilation. Personnellement, je préfère ce dernier style car il reflète mieux mon intention et je n'ai pas tendance à faire cette erreur.Il en va de même pour la conversion de la valeur renvoyée par
malloc
: je préfère être explicite dans la programmation et je vérifie généralement pour inclure les fichiers d'en-tête pour toutes les fonctions que j'utilise.la source
stdlib.h
est déjà une erreur en soi, même si vous n'obtenez que des avertissements de "déclaration implicite".L'un des bons arguments de plus haut niveau contre la diffusion du résultat de
malloc
est souvent ignoré, même si, à mon avis, il est plus important que les problèmes de niveau inférieur bien connus (comme la troncature du pointeur lorsque la déclaration est manquante).Une bonne pratique de programmation consiste à écrire du code, qui est aussi indépendant que possible du type. Cela signifie, en particulier, que les noms de types doivent être mentionnés dans le code le moins possible ou mieux ne pas être mentionnés du tout. Cela s'applique aux transtypages (évitez les transtypages inutiles), aux types comme arguments de
sizeof
(évitez d'utiliser des noms de type danssizeof
) et, généralement, à toutes les autres références aux noms de type.Les noms de type appartiennent aux déclarations. Autant que possible, les noms de type doivent être limités aux déclarations et uniquement aux déclarations.
De ce point de vue, ce bit de code est mauvais
int *p; ... p = (int*) malloc(n * sizeof(int));
et c'est bien mieux
int *p; ... p = malloc(n * sizeof *p);
non pas simplement parce qu'il "ne
malloc
transforme pas le résultat de ", mais plutôt parce qu'il est indépendant du type (ou indépendant du type, si vous préférez), parce qu'il s'ajuste automatiquement à n'importe quel typep
déclaré avec, sans nécessiter aucune intervention de l'utilisateur.la source
Les fonctions non prototypées sont supposées retourner
int
.Vous lancez donc un
int
vers un pointeur. Si les pointeurs sont plus larges queint
s sur votre plateforme, il s'agit d'un comportement très risqué.De plus, bien sûr, certaines personnes considèrent les avertissements comme des erreurs, c'est-à-dire que le code doit être compilé sans eux.
Personnellement, je pense que le fait que vous n'ayez pas besoin de convertir
void *
en un autre type de pointeur est une fonctionnalité en C, et considère que le code est cassé.la source
void*
.int
." - Voulez-vous dire qu'il est possible de changer le type de retour des fonctions non prototypées?#ifdef __cplusplus \nextern "C" { \n#endif static inline uint16_t swb(uint16_t a) {return ((a << 8) | ((a >> 8) & 0xFF); } \n#ifdef __cplusplus\n } \n#endif
. Maintenant, pourquoi vous voudriez appeler malloc dans une fonction statique en ligne, je ne sais vraiment pas, mais les en-têtes qui fonctionnent dans les deux sont à peine inconnus.Si vous faites cela lors de la compilation en mode 64 bits, votre pointeur renvoyé sera tronqué à 32 bits.
EDIT: Désolé d'être trop bref. Voici un exemple de fragment de code à des fins de discussion.
Supposons que le pointeur de tas retourné soit quelque chose de plus grand que ce qui est représentable dans un int, disons 0xAB00000000.
Si malloc n'est pas prototypé pour renvoyer un pointeur, la valeur int retournée sera initialement dans un registre avec tous les bits significatifs définis. Maintenant, le compilateur dit: "OK, comment puis-je convertir et int en pointeur". Ce sera soit une extension de signe, soit une extension zéro des 32 bits de poids faible que malloc "retourne" en omettant le prototype. Puisque int est signé, je pense que la conversion sera une extension de signe, qui dans ce cas convertira la valeur à zéro. Avec une valeur de retour de 0xABF0000000, vous obtiendrez un pointeur non nul qui vous amusera également lorsque vous essayez de le déréférencer.
la source
Une règle logicielle réutilisable:
Dans le cas de l'écriture d'une fonction en ligne dans laquelle utilisé malloc (), afin de la rendre réutilisable pour le code C ++ également, veuillez faire un casting de type explicite (par exemple (char *)); sinon le compilateur se plaindra.
la source
malloc
/free
pour les deux est susceptible d'être mieux que d' essayer d'utilisermalloc
en C etnew
en C ++, en particulier si les structures de données sont partagées entre C et C ++ code et il est possible qu'un objet soit créé en code C et publié en code C ++ ou vice versa.Un pointeur void en C peut être assigné à n'importe quel pointeur sans cast explicite. Le compilateur donnera un avertissement mais il peut être réutilisable en C ++ par conversion de type en type
malloc()
correspondant. Sans moulage de type, il peut également être utilisé en C , car C n'est pas une vérification de type stricte . Mais C ++ est strictement une vérification de type , il est donc nécessaire de taper castmalloc()
en C ++.la source