IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C Discussion :

Fonction malloc en C


Sujet :

C

  1. #21
    Expert confirmé

    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    10 610
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 10 610
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par DaZumba Voir le message
    La FAQ pourrait se contenter de traduire la C FAQ (7.7 et 7.7b).
    ce serait une solution, bien que je n'aime pas le titre du 7.7b, qui est biaisé..

    Ce qu'il dit d'ailleurs dans la dernière ligne..

    Je préférerais un titre comme "pourquoi certains trouvent qu'il ne faut pas caster le retour de malloc?"






    Je pense que tout ce débat et cette utilisation vient de l'utilisation d'outils comme DEVC++ et autres, qui compilent autant du C que du C++ sans être pour autant généralistes comme gcc.. (d'ailleurs, le fait de faire un point d'entrée commun entre C et C++ est à mon avis délicat, de même que de parler d'un compilateur C++ ou d'extensions cpp)

    Un gcc avec les bons flags indiquent de suite qu'on a oublié un fichier d'entête (en particulier stdlib.h, ne serait-ce que pour main)..


    Enfin, comme je l'ai dit plus haut, si il fallait enlever tout ce qui peut faire tromper un débutant sous C, il ne resterait plus grand chose.. ([I]pas de **, ni de ***, ni de ++i ou i++, pas de &(tab) ou de (*struct).x ...)

  2. #22
    Membre éprouvé
    Homme Profil pro
    Inscrit en
    Mars 2011
    Messages
    102
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Mars 2011
    Messages : 102
    Par défaut
    Bon.. désolé de remettre ça sur le tapis, mais j'aurais besoin d'explication concernant les recommandations du CERT.

    d'après ce qu'il a été dit sur dans ce topic, le cast d'un malloc est utile pour certains surtout pour rendre le code plus lisible et éviter les erreurs.
    Mais je n'ai pas lu (ou alors mal..) le fait qu'avec un void *, si on se trompe de type, le compilateur ne bronchera pas :

    The argument to malloc() can be any value of (unsigned) type size_t. If the program uses the allocated storage to represent an object (possibly an array) whose size is greater than the requested size, the behavior is undefined. The implicit pointer conversion lets this slip by without complaint from the compiler.

    Consider the following example:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    #include <stdlib.h>
     
    typedef struct gadget gadget;
    struct gadget {
      int i;
      double d;
    };
     
    typedef struct widget widget;
    struct widget {
      char c[10];
      int i;
      double d;
    };
     
    widget *p;
     
    /* ... */
     
    p = malloc(sizeof(gadget)); /* imminent problem */
    if (p != NULL) {
      p->i = 0;               /* undefined behavior */
      p->d = 0.0;             /* undefined behavior */
    }
    An implementation may add padding to a gadget or widget so that sizeof(gadget) equals sizeof(widget), but this is highly unlikely. More likely, sizeof(gadget) is less than sizeof(widget). In that case

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    p = malloc(sizeof(gadget)); /* imminent problem */
    quietly assigns p to point to storage too small for a widget. The subsequent assignments to p->i and p->d will most likely produce memory overruns.

    Casting the result of malloc() to the appropriate pointer type enables the compiler to catch subsequent inadvertent pointer conversions. When allocating individual objects, the "appropriate pointer type" is a pointer to the type argument in the sizeof expression passed to malloc().

    In this code example, malloc() allocates space for a gadget and the cast immediately converts the returned pointer to a gadget *:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    widget *p;
     
    /* ... */
     
    p = (gadget *)malloc(sizeof(gadget)); /* invalid assignment */
    This lets the compiler detect the invalid assignment because it attempts to convert a gadget * into a widget *.
    source: https://www.securecoding.cert.org/co...allocated+type

  3. #23
    Expert confirmé

    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    10 610
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 10 610
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par Trankille Voir le message
    Bon.. désolé de remettre ça sur le tapis, mais j'aurais besoin d'explication concernant les recommandations du CERT.

    d'après ce qu'il a été dit sur dans ce topic, le cast d'un malloc est utile pour certains surtout pour rendre le code plus lisible et éviter les erreurs.
    Mais je n'ai pas lu (ou alors mal..) le fait qu'avec un void *, si on se trompe de type, le compilateur ne bronchera pas :
    D'une part je te remercie d'avoir fourni un support de qualité à mes recommandations :

    Casting the result of malloc() to the appropriate pointer type enables the compiler to catch subsequent inadvertent pointer conversions. When allocating individual objects, the "appropriate pointer type" is a pointer to the type argument in the sizeof expression passed to malloc().
    ..
    This lets the compiler detect the invalid assignment because it attempts to convert a gadget * into a widget *.


    Par contre, en ce qui concerne le void*, d'une part le cast est obligatoire, d'autre part bien évidemment il ne peut y avoir de vérification, en tous cas par rapport à la valeur entrée...

    Pour la valeur de sortie, il y a automatiquement vérification puisqu'il y a cast obligatoire.

    Par contre, s'assurer que le type casté en entrée est le même que celui utilisé en sortie est non seulement impossible , car il faudrait analyser 'ensemble du code et des mouvements de varaibles et suivre les noms des varaibles, mais souvent non souhaitable, car justement souvent un cast en void* permet de faire une fonction "flexible"...

  4. #24
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 801
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 801
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Trankille Voir le message
    Bon.. désolé de remettre ça sur le tapis, mais j'aurais besoin d'explication concernant les recommandations du CERT...
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    widget *p;
     
    /* ... */
     
    p = (gadget *)malloc(sizeof(gadget)); /* invalid assignment */
    Salut

    Tu as trouvé là un SUPERBE exemple donnant au-moins une raison de caster malloc().

    Toutefois, et bien que je sois d'accord avec beaucoup d'arguments de souviron34, pour ma part je penche quand-même en faveur définitive du non cast.

    Il faut bien comprendre qu'à la base, le C est un langage fait pour ceux qui savent faire et c'est bien précisé que "le programmeur sait ce qu'il fait". Donc le programmeur est sensé, à priori, ne pas se vautrer ; ni en oubliant d'inclure stdlib, ni en confondant le type gadget avec le type widget et donc ces deux arguments, l'un en faveur du "non cast" et l'autre en faveur du cast sont tous deux anihilés par ce prédicat.
    Bien sûr il s'agit ici d'un voeu pieu (que celui qui n'est jamais resté scotché 4h sur son code parce qu'il avait écrit "if (pt=NULL)" au lieu de "if (pt == NULL)" me jette la première pierre) mais bon, si le programmeur se vautre, il a autant de chance de se vautrer dans une direction que dans l'autre et là encore les deux arguments s'annulent devant ce fait.

    Reste toutefois l'argument ultime => Inutile de caster malloc() parce que justement, le cast d'un void* est inutile. Parce que si on commence à faire de l'inutile, alors il n'y a plus de limite et un jour on verra quelqu'un arriver en disant "il faut vérifier chaque affectation if ((i=5) == 5) parce qu'on n'est pas à l'abri d'une erreur (en fait je voulais mettre 6)" et là, c'est la porte ouverte au grand n'importe quoi.
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  5. #25
    Membre éprouvé
    Homme Profil pro
    Inscrit en
    Mars 2011
    Messages
    102
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Mars 2011
    Messages : 102
    Par défaut
    Citation Envoyé par Sve@r Voir le message
    Salut
    Il faut bien comprendre qu'à la base, le C est un langage fait pour ceux qui savent faire et c'est bien précisé que "le programmeur sait ce qu'il fait". Donc le programmeur est sensé, à priori, ne pas se vautrer
    on va dire que ce n'est pas simplement pour celui qui développe mais surtout pour la maintenance du code et sa relecture pour les (très) gros projets ^^

    merci pour les réponses, ça m'a montré les deux points de vue qui pour moi se valent.
    Mais je penche pour le cast quand même notamment pour les programmes "sensibles".

  6. #26
    Expert confirmé

    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    10 610
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 10 610
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par Sve@r Voir le message
    ni en confondant le type gadget avec le type widget et donc ces deux arguments, l'un en faveur du "non cast" et l'autre en faveur du cast sont tous deux anihilés par ce prédicat.
    ça n'est pas une question de confondre, mais de pouvoir changer facilement de type tout en ayant une vérification qu'on n'a rien oublié..

    Si tu as mis partout des cast, alors si tu modifies le type "à la main", tu auras instantanément une erreur à la compil... que tu n'auras pas si tu ne l'as pas mis..

    Par contre, cet argument tombe si tu utilises un outil (que ce soit via un EDI soit via un sed..)



    Mais je maintiens à cause de la lisibilité...



    Citation Envoyé par Sve@r Voir le message
    Reste toutefois l'argument ultime => Inutile de caster malloc() parce que justement, le cast d'un void* est inutile.
    tu t'est trompé je suppose....

    Le cast d'un void* est obligatoire... (dans le cas de malloc ça ne l'est pas puisque on ne se sert pas de la structure sauf pour la taille)..

    Mais si tu as :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    struct {
        void *data ;
    } mastruct ;

    pour se servir de data il faudra bien caster à un moment donné... Donc pourquoi utiliser 2 approches différentes ???

    malloc est une exception et pas une règle..

    En déduire donc une règle est pour le moins osé...

    Et à mon avis peu cohérent...

  7. #27
    gl
    gl est déconnecté
    Rédacteur

    Homme Profil pro
    Inscrit en
    Juin 2002
    Messages
    2 165
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Juin 2002
    Messages : 2 165
    Par défaut
    Citation Envoyé par souviron34 Voir le message
    tu t'est trompé je suppose....

    Le cast d'un void* est obligatoire... (dans le cas de malloc ça ne l'est pas puisque on ne se sert pas de la structure sauf pour la taille)..
    Ce qu'il voulait dire, je suppose, c'est qu'en C, les conversions de void* vers T* et de T* vers void* (pour tout type T) sont implicites. Il n'est donc pas obligatoire de caster explicitement de telles conversions.

  8. #28
    Expert confirmé

    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    10 610
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 10 610
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par gl Voir le message
    Ce qu'il voulait dire, je suppose, c'est qu'en C, les conversions de void* vers T* et de T* vers void* (pour tout type T) sont implicites. Il n'est donc pas obligatoire de caster explicitement de telles conversions.
    Admettons...

    Mais ça ne répond pas à :

    Citation Envoyé par souviron34 Voir le message
    pour se servir de data il faudra bien caster à un moment donné... Donc pourquoi utiliser 2 approches différentes ???



    Prenons l'exemple des callbacks que je connais bien...

    La callback d'un widget a en paramètre une structure dépendante du widget plus une structure de données client (sous formes de pointeurs).

    Cependant, tout widget complexe hérite (au sens réel de classe) de widgets plus simples.

    Sa structure dépendante est "recouvrable" en partie par la structure plus simple (via des unions).

    Si à l'intérieur de la callback on a besoin d'un paramètre de la structure du widget plus simple, il me semble nettement plus clair à la lecture de mettre :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    void Method ( void *CallbackStruct, void *Data )
    {
    StructComplexe *CompStruct = (StructComplexe *) Callbackstruct ;
    StructSimple *SimpStruct = (StructSimple *) CallbackStruct :
    ...
    }
    que de mettre :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    void Method ( void *CallbackStruct, void *Data )
    {
    StructComplexe *CompStruct = Callbackstruct ;
    StructSimple *SimpStruct = CallbackStruct :
    ...
    }
    où le lecteur se posera des questions à savoir pourquoi le même pointeur est assigné à 2 structures différentes... Alors qu'avec le cast il sait que on considère le pointeur de 2 manières différentes, comme étant implicitement 2 pointeurs différents.




    Quant aux conversions en sens inverse, si les flags de compil sont mis avec vérification des prototypes et/ou des cast, on se fait jeter proprement si on assigne un pointeur *StructComplexe à un void* sans cast explicite...


    Encore un exemple avec les callbacks ci-dessus.. Si on enregistre la fonction Method sans caster avec void* et que le flag -Wstrict_prototypes est mis, on se fera jeter...


    Maintenant, c'est effectivement une question de goût, mais en tous cas, ta citation même ("implicite"), ne plaide ni pour une règle, ni pour un comportement à recommander...

  9. #29
    gl
    gl est déconnecté
    Rédacteur

    Homme Profil pro
    Inscrit en
    Juin 2002
    Messages
    2 165
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Juin 2002
    Messages : 2 165
    Par défaut
    Citation Envoyé par souviron34 Voir le message
    Quant aux conversions en sens inverse, si les flags de compil sont mis avec vérification des prototypes et/ou des cast, on se fait jeter proprement si on assigne un pointeur *StructComplexe à un void* sans cast explicite...
    Pourtant c'est ce qui est fait lorsqu'on utilise des fonctions style memcpy() ou memset() sans cast explicite des paramètres (et la forme idiomatique semble plutôt être de ne pas caster les paramètres de ces fonctions justement). Et sur les compilateurs que j'utilise, je ne connais pas d'option permettant de lever une erreur ou un warning dans ce cas (et je viens de faire le test avec -Wstrict-prototypes qui ne leve rien dans ce cas).


    Sinon, mon propos portait uniquement sur la remarque que j'ai citée. Pas sur la question de fond faut-il ou non caster explicitement void* en C, je n'ai pas (plus) d'avis vraiment tranché à ce sujet. J'aurais plutôt tendance à gérer au cas par cas.

  10. #30
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 801
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 801
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par gl Voir le message
    Ce qu'il voulait dire, je suppose, c'est qu'en C, les conversions de void* vers T* et de T* vers void* (pour tout type T) sont implicites. Il n'est donc pas obligatoire de caster explicitement de telles conversions.
    Exact, c'est bien ce que je voulais dire.
    Je sais bien que si j'ai un void *pt et que je veux utiliser *pt, il faudra que j'indique comment je l'utilise donc que je le caste lors de l'utilisation.
    Ce que je voulais dire, c'est que je peux copier un void* (donc ce que renvoie malloc) dans n'importe quel <type>* sans avoir besoin de caster.

    Sinon bien le coup des callback. Finalement je ne sais plus trop quoi dire donc je vais me ranger de l'avis de gl => voir au cas par cas...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

Discussions similaires

  1. aide sur fonction malloc
    Par chuko dans le forum C
    Réponses: 4
    Dernier message: 27/08/2008, 12h21
  2. Le bloc renvoyé par la fonction malloc
    Par clement_ dans le forum C
    Réponses: 4
    Dernier message: 08/10/2007, 15h12
  3. Réponses: 20
    Dernier message: 13/02/2007, 11h50
  4. Fonction malloc pour allocation
    Par Maria1505 dans le forum C
    Réponses: 6
    Dernier message: 06/11/2006, 16h38
  5. fonction malloc en c
    Par Invité(e) dans le forum C
    Réponses: 2
    Dernier message: 15/04/2006, 23h34

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo