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

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé
    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
    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
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 397
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 397
    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 éclairé
    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
    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é.

  4. #4
    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 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 ;
    }

  5. #5
    Membre Expert
    Inscrit en
    Décembre 2004
    Messages
    1 478
    Détails du profil
    Informations forums :
    Inscription : Décembre 2004
    Messages : 1 478
    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.

  6. #6
    Membre éclairé
    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
    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.

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

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 397
    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 éclairé
    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
    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 Expert
    Inscrit en
    Décembre 2004
    Messages
    1 478
    Détails du profil
    Informations forums :
    Inscription : Décembre 2004
    Messages : 1 478
    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
    Expert éminent
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 68
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    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;
    }

  11. #11
    Membre éclairé
    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
    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?

  12. #12
    Expert confirmé

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    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())

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

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    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...

  14. #14
    Expert confirmé

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    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.

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