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 :

allocation mémoire puis test générique


Sujet :

C

  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    613
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2007
    Messages : 613
    Points : 406
    Points
    406
    Par défaut allocation mémoire puis test générique
    Bonjour
    J'avais créé des fonctions d'allocation pour éviter de refaire a chaque fois les test de succés comme ca :
    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
     
    //Pour un int par exemple
    int allocation_int(int ** pt) {
       *pt = malloc(TAILLE*sizeof(int));
        if(!(*pt)){
     	trace("Error : Allocation memoire\n");
    	return 0;
        }
        return 1;
    }
     
    //et je l'apelle comme ca :
    int * test, *test2;
    if(!allocation_int(&test) || !allocation_int(&test2)){
    ...
    }
    Presenté comme ca, pas grand interet mais pour en allouer plein d'un coup c'est plus pratique.

    Je voudrais en faire un générique et j'ai fait :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    int allocation_type (void ** pt) {
        *pt = malloc(TAILLE*sizeof(**pt));
        if(!(*pt)){
     	trace("Error : Allocation memoire\n");
    	return 0;
        }
        return 1;
    }
     
    //que j'apelle comme ca :
    if(!allocation_type(&test)
    Et j'obtient cette erreur :
    warning: passing arg 1 of `allocation_type' from incompatible pointer type
    Pourquoi?

    merci

  2. #2
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Un void** n'est pas générique, seul un void* l'est.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  3. #3
    Membre expérimenté
    Inscrit en
    Décembre 2004
    Messages
    1 478
    Détails du profil
    Informations forums :
    Inscription : Décembre 2004
    Messages : 1 478
    Points : 1 664
    Points
    1 664
    Par défaut
    La conversion implicite, c'est entre void * et les pointeurs des autres types. void ** n'est pas un "double pointeur generique". Le plus simple, c'est de renvoyer un void * ou NULL si l'allocation a echoue... mais c'est exactement ce que malloc() fait de toute facon ! Ton wrapper n'est pas utile.

  4. #4
    Membre averti
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    613
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2007
    Messages : 613
    Points : 406
    Points
    406
    Par défaut
    mais si j'utilise pas un void ** mon pointeur ne sera pas modifié, et l'adresse de test ne pointera donc pas vers la bonne adresse mémoire non?
    en tout cas c'est ce qu'il se passait quand je faisait allocation_int(int * pt) : pt était passé par copie et pas modifié.

  5. #5
    Membre averti
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    613
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2007
    Messages : 613
    Points : 406
    Points
    406
    Par défaut
    Citation Envoyé par DaZumba Voir le message
    La conversion implicite, c'est entre void * et les pointeurs des autres types. void ** n'est pas un "double pointeur generique". Le plus simple, c'est de renvoyer un void * ou NULL si l'allocation a echoue... mais c'est exactement ce que malloc() fait de toute facon ! Ton wrapper n'est pas utile.
    Ma fonction permet de faire des tests enchainés sans tester NULL a chaque fois. Et j'ai pas tout mis, car elle initialise à 0 (memset) la mémoire.

  6. #6
    Expert éminent sénior
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Points : 20 985
    Points
    20 985
    Par défaut
    Citation Envoyé par pasdeface Voir le message
    Je voudrais en faire un générique et j'ai fait :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    int allocation_type (void ** pt) {
        *pt = malloc(TAILLE*sizeof(**pt));
        if(!(*pt)){
     	trace("Error : Allocation memoire\n");
    	return 0;
        }
        return 1;
    }
     
    //que j'apelle comme ca :
    if(!allocation_type(&test)
    Et j'obtient cette erreur :
    <...>
    Pourquoi?
    Parce que le type n'est pas bon. Le seul type de pointeur de données générique en C est void *. Le problème, c'est qu'il n'y a pas de vérification.

    Tu peux donc faire :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    int allocation_type (void *pt, size_t size) {
    void **ppt = pt;
        *ppt = malloc(size);
        if(*ppt==NULL){
     	trace("Error : Allocation memoire\n");
    	return 0;
        }
        return 1;
    }
    mais ça n'a pas un grand intérêt... Ca, peut être...
    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
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
     
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
     
    #define trace(s) printf ("Error : %s at %s:%d\n", s, __FILE__, __LINE__)
     
    int allocation_type (void *pt, size_t size)
    {
       int ok = 0;
       if (pt != NULL)
       {
          void **ppt = pt;
          if (*ppt == NULL)
          {
             *ppt = malloc (size);
             if (*ppt == NULL)
             {
                trace ("Allocation memoire");
             }
             else
             {
                ok = 1;
             }
          }
          else
          {
             trace ("Deja alloue");
          }
       }
       else
       {
          trace ("Pointeur NULL");
       }
       return ok;
    }
     
    int main (void)
    {
       char *p = NULL;
       int ok;
     
       ok = allocation_type (NULL, 10);
     
       if (ok)
       {
          strcpy (p, "hello");
          printf ("'%s'\n", p);
       }
       ok = allocation_type (&p, 10);
     
       if (ok)
       {
          strcpy (p, "hello");
          printf ("'%s'\n", p);
       }
       ok = allocation_type (&p, 10);
     
       if (ok)
       {
          strcpy (p, "hello");
          printf ("'%s'\n", p);
       }
       return 0;
    }
    Pas de Wi-Fi à la maison : CPL

  7. #7
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Tu peux toujours faire une macro qui vérifie que la variable est un pointeur, puis caste...

    D'autant que ta fonction ne devrait pas compiler, sizeof(void) est bizarre...

    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    int allocation_type (void ** pp, size_t nElts, size_t s) {
        *pt = malloc(nElts*s);
        if((*pt)==NULL){
     	trace("Error : Allocation memoire\n");
    	return 0;
        }
        return 1;
    }
    #define ALLOC(p,n) allocation_type((void**)&(p), (n), sizeof(*(p)))
     
    //et appeler comme ca :
    int * test, *test2;
    if(!ALLOC(test, TAILLE) || !ALLOC(test2, TAILLE)){
    ...
    }
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  8. #8
    Membre averti
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    613
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2007
    Messages : 613
    Points : 406
    Points
    406
    Par défaut
    Citation Envoyé par Médinoc Voir le message

    D'autant que ta fonction ne devrait pas compiler, sizeof(void) est bizarre...
    c'est sizeof du type pointé par void...

  9. #9
    Membre expérimenté
    Inscrit en
    Décembre 2004
    Messages
    1 478
    Détails du profil
    Informations forums :
    Inscription : Décembre 2004
    Messages : 1 478
    Points : 1 664
    Points
    1 664
    Par défaut
    Il est vraiment difficile de faire un wrapper generique de malloc() qui ait quelque utilite, tout simplement parce qu'il faut de toute facon verifier la valeur de retour du wrapper... Il y a bien la solution type xmalloc() qui exit() si l'allocation a echoue, mais dans la plupart des situations reelles, c'est d'un usage assez douteux. Restent les wrappers dedies a des situations bien determinees pour une application donnee (genre memory manager, memory pools, ou un truc super specifique genre "allouer deux tableaux d'entiers et un tableau de doubles"). Mais un wrapper generique, franchement, je ne suis pas convaincu...

  10. #10
    Membre averti
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    613
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2007
    Messages : 613
    Points : 406
    Points
    406
    Par défaut
    Citation Envoyé par Emmanuel Delahaye Voir le message
    Tu peux donc faire :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    int allocation_type (void *pt, size_t size) {
    void **ppt = pt;
        *ppt = malloc(size);
        if(*ppt==NULL){
     	trace("Error : Allocation memoire\n");
    	return 0;
        }
        return 1;
    }
    Merci ca semble marcher.
    J'ai juste un doute sur le sizeof. Je voudrais pouvoir faire un malloc en fonction de la taille du type sans passer par la taille en parametre.
    J'ai essayé sizeof(*ppt) ou sizeof(pt) et ca me donne bien la taille du type, est ce correct?

  11. #11
    Membre averti
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    613
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2007
    Messages : 613
    Points : 406
    Points
    406
    Par défaut
    Citation Envoyé par DaZumba Voir le message
    Il est vraiment difficile de faire un wrapper generique de malloc() qui ait quelque utilite, tout simplement parce qu'il faut de toute facon verifier la valeur de retour du wrapper... Il y a bien la solution type xmalloc() qui exit() si l'allocation a echoue, mais dans la plupart des situations reelles, c'est d'un usage assez douteux. Restent les wrappers dedies a des situations bien determinees pour une application donnee (genre memory manager, memory pools, ou un truc super specifique genre "allouer deux tableaux d'entiers et un tableau de doubles"). Mais un wrapper generique, franchement, je ne suis pas convaincu...
    le wrapper peut tester la retour du malloc NULL et renvoyer 0 ou 1. Ensuite on peut faire d'autrs choses à l'interieur comme initialiser la mémoire (memset).
    Tout ca avec l'appel d'une fonction dont on a juste a tester le retour 0 ou 1.

  12. #12
    Expert éminent

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Points : 6 911
    Points
    6 911
    Par défaut
    Citation Envoyé par Emmanuel Delahaye Voir le message
    Tu peux donc faire :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    int allocation_type (void *pt, size_t size) {
    void **ppt = pt;
        *ppt = malloc(size);
        if(*ppt==NULL){
     	trace("Error : Allocation memoire\n");
    	return 0;
        }
        return 1;
    }
    Comportement indefini si on passe a pt autre chose que l'adresse d'un void*. (Penser par exemple qu'on peut avoir sizeof(int*) < sizeof(void*), on se met a ecrire ou on ne peut pas si on passe &mon_int_ptr a allocation_type())
    Les MP ne sont pas là pour les questions techniques, les forums sont là pour ça.

  13. #13
    Expert éminent sénior
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Points : 20 985
    Points
    20 985
    Par défaut
    Citation Envoyé par Jean-Marc.Bourguet Voir le message
    Comportement indefini si on passe a pt autre chose que l'adresse d'un void*. (Penser par exemple qu'on peut avoir sizeof(int*) < sizeof(void*), on se met a ecrire ou on ne peut pas si on passe &mon_int_ptr a allocation_type())
    Moui, ça remet en cause beaucoup de code générique et de callbacks avec des contextes génériques...
    Pas de Wi-Fi à la maison : CPL

  14. #14
    Expert éminent

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Points : 6 911
    Points
    6 911
    Par défaut
    Citation Envoyé par Emmanuel Delahaye Voir le message
    Moui, ça remet en cause beaucoup de code générique et de callbacks avec des contextes génériques...
    Si c'est bien le genre de contextes auxquels je pense, on converti generalement un void* en un pointeur vers une structure, ce qui est valide.

    La regle est qu'on ne peut convertir un void* qu'en un pointeur du meme type (aux qualifications cv pres) que celui qui a servi a creer le void*. Exactement comme les unions. Exactement la raison pour laquelle j'aime pas la regle du C qui permet de convertir implicitement un void* en n'importe quel pointeur, devoir mettre un cast incite a reflechir au fait qu'un probleme peut arriver.

    On peut considerer que les machines pour lesquelles ca ne marche pas ne sont pas importantes, ce qui n'est pas tout a fait faux. Mais je n'ai aucune idee du bordel qu'un optimiseur peut venir mettre si on ne respecte pas la regle, depuis que j'en ai vu un avoir des effets non causals, je me mefie.
    Les MP ne sont pas là pour les questions techniques, les forums sont là pour ça.

  15. #15
    Membre expérimenté
    Inscrit en
    Décembre 2004
    Messages
    1 478
    Détails du profil
    Informations forums :
    Inscription : Décembre 2004
    Messages : 1 478
    Points : 1 664
    Points
    1 664
    Par défaut
    Citation Envoyé par pasdeface Voir le message
    le wrapper peut tester la retour du malloc NULL et renvoyer 0 ou 1. Ensuite on peut faire d'autrs choses à l'interieur comme initialiser la mémoire (memset).
    Tout ca avec l'appel d'une fonction dont on a juste a tester le retour 0 ou 1.
    La difficulté dans ta fonction est que tu passes le pointeur qui doit recevoir l'adresse du bloc alloué comme argument, et tu retrouves avec un void **.
    Tu ferais:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    void *my_extended_malloc(size_t size, int setvalue)
    {
      void *ptr = malloc(size);
      if (ptr != NULL)
      {
        memset(ptr, setvalue, size);
      }
      return ptr;
    }
    Tu n'aurais pas à faire l'indirection. Si tu veux faire toute une suite de malloc() (j'utiliserais plutôt un memory pool dans ce cas, mais admettons), alors tu peux éviter l'indirection en regroupant les adresses dans une structure que tu passes en argument, mais ce ne sera pas très flexible.

  16. #16
    Expert éminent sénior

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

    Informations forums :
    Inscription : Janvier 2007
    Messages : 10 603
    Points : 17 913
    Points
    17 913
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par pasdeface Voir le message
    mais si j'utilise pas un void ** mon pointeur ne sera pas modifié, et l'adresse de test ne pointera donc pas vers la bonne adresse mémoire non?.
    bien sur que si..

    void * indique un pointeur void.. Riuen n'empeche que ce pointeur soit lui meme un pointeur..

    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
    25
    void Fonction ( void *toto )
    {
      int **titi = (int **)toto ;
      int     i ;
     
      *titi = malloc ( 8*sizeof(int) );
        if ( *titi != NULL )
          {
             for ( i = 0 ; i < 8 ; i++ )
                (*titi)[i] = i ;
          }
    }
     
    int main ( void )
    {
       int *tab=NULL, i ;
     
       Fonction((void *)&tab);
     
       if ( tab != NULL )
         for ( i = 0 ; i < 8 ; i++ )
           fprintf ( stderr, "\nValeur du tableau a la case %d : %d",i,tab[i]);
     
      return EXIT_SUCCESS ;
    }
    "Un homme sage ne croit que la moitié de ce qu’il lit. Plus sage encore, il sait laquelle".

    Consultant indépendant.
    Architecture systèmes complexes. Programmation grosses applications critiques. Ergonomie.
    C, Fortran, XWindow/Motif, Java

    Je ne réponds pas aux MP techniques

Discussions similaires

  1. Pb d'allocation mémoire malloc
    Par oz80 dans le forum C++
    Réponses: 5
    Dernier message: 18/11/2005, 17h23
  2. Limite Allocation Mémoire d'un tableau d'entier
    Par l9ft b9hind dans le forum C++
    Réponses: 5
    Dernier message: 27/10/2005, 19h29
  3. Allocation mémoire
    Par DestyNov@ dans le forum C++
    Réponses: 9
    Dernier message: 23/08/2005, 08h09
  4. [Pointeur] Allocation mémoire
    Par Rayek dans le forum Langage
    Réponses: 22
    Dernier message: 20/05/2005, 10h26
  5. Allocation mémoire dynamique
    Par ITISAR dans le forum VB 6 et antérieur
    Réponses: 6
    Dernier message: 21/01/2005, 09h59

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