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 :

Programmation Générique en C


Sujet :

C

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre actif
    Inscrit en
    Décembre 2009
    Messages
    95
    Détails du profil
    Informations forums :
    Inscription : Décembre 2009
    Messages : 95
    Par défaut Programmation Générique en C
    Bonjour à tous,

    Voilà j'ai un programme qui fonctionne (pour l'instant) très bien mais ce, avec un seul et unique type de données, un struct déclaré comme ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    typedef struct{
        uint16_t type;
        uint64_t word;
    } obj;
    J'aurais aimé faire en sorte de remplacer le uint64_t word par deux tableaux de type uint8_t de longueurs variables. Certains me diront que je n'ai qu'a stocker deux variables de type uint8_t* qui seront allouées dynamiquement à l'exécution mais cela me fait stocker deux pointeurs supplémentaires, ce que je ne souhaite pas. La mémoire utilisée est d'une importance cruciale pour moi.

    J'ai cherché sur internet comment faire ceci sans avoir à dupliquer dupliquer mon code pour toutes les tailles de tableau possibles (dans une certaine limite), je ne souhaite pas traiter séparément chaque cas correspondant à une longueur x et y de mes tableaux. Je suis tombé sur ce tuto de programmation générique en C :
    http://cecilsunkure.blogspot.de/2012...ming-in-c.html

    J'ai donc écris ce code dans un fichier obj.h (j'ai changé les noms de variables et structures):

    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
     
    #ifndef DEF_OBJ
    #define DEF_OBJ
     
    #include <stdio.h>
    #include <stdlib.h>
    #include <stdint.h>
     
    #define DECLARE_TAB(A,B)                           \
        typedef struct _LINE_##A##_##B                  \
        {                                               \
            uint8_t tab1[A];                            \
            uint8_t tab2[B];                         \
        } LINE_##A##_##B;
     
    #define DECLARE_OBJ(A,B)                             \
        typedef struct _OBJ                              \
        {                                               \
            uint16_t type;                              \
            LINE_##A##_##B obj;                   \
        } OBJ;              \
    \
        OBJ *CREATE_OBJ(A,B);
     
    #define CREATE_OBJ(A,B)                              \
        OBJ *CREATE_OBJ(A,B)                              \
        {                                               \
            return (OBJ*)malloc(sizeof(DECLARE_OBJ(A,B)));\
        }
     
    #endif
    Ma première question est donc : puis-je utiliser le type OBJ dans du code qui n'est pas du macro, c'est à dire qui n'est pas executé par le préprocesseur ? Ou suis-je obligé de réécrire tout mon programme (ce que je ne ferais pas) dans ce style macro si je veux pouvoir l'utiliser ?
    Ma deuxième question est : ce code est-il valide d'après vous ?

    Je vous remercie encore de votre aide et vous souhaite une excellente journée et/ou soirée

  2. #2
    Expert confirmé
    Avatar de Kannagi
    Homme Profil pro
    cyber-paléontologue
    Inscrit en
    Mai 2010
    Messages
    3 226
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : cyber-paléontologue

    Informations forums :
    Inscription : Mai 2010
    Messages : 3 226
    Par défaut
    Alors je vais répondre a ta derniere question non ce genre de code n'est pas valide pour moi , rien ne empeche mais je trouve que c'est abusé les macro , en plus pour faire des struct
    Pour la fonction , il y a le inline , la ça me semble un peu dangereux de faire une fonction sur du macro elle n'est pas appelé , elle ne fait que la creer .

    Déjà as tu pensé a utiliser le mot clé union ou les comparaison/decage bit a bit , qui permet justement ecrire/de comparer sur chaque bit (ou chaque octet).

  3. #3
    Membre actif
    Inscrit en
    Décembre 2009
    Messages
    95
    Détails du profil
    Informations forums :
    Inscription : Décembre 2009
    Messages : 95
    Par défaut
    Merci de ta réponse Kennagi

    Alors, quand tu dis que ce code n'est pas valide pour toi, tu veux dire que tu n'écrirais pas ce code si c'était ton programme, mais que potentiellement il marche quand même ?

    L'idée du code que j'ai posté est juste de présenter les struct que je souhaite créer, si le code marche j'en viendrais à créer toutes les fonctions associées pour la manipulation de ces struct. Je veux juste savoir si je peut utiliser le type OBJ, qui enveloppe le type "dynamique" LINE_##A##_##B, dans une fonction qui n'est pas du macro. En réalité, j'ai essayé d'utiliser ce type dans ma fonction main() (avec un #include "obj.h") mais j'obtiens juste une erreur du compilateur, "type non défini"

    J'ai bien pensé au mot clé inline mais celui-ci ne résout pas mon problème, à savoir que je souhaite écrire un seul code pour une multitude de types sans avoir a passer par des void*. Le problème de l'union, c'est que l'espace utilisé est celui du plus grand type stocké. Donc si je déclare un union contenant par example uint8_t t1[1], uint8_t t2[2], ..., uint8_t t64[64], peu importe le tableau tx que j'utilise, mon union utilisera en mémoire 64*sizeof(uint8_t)

  4. #4
    Expert confirmé
    Avatar de Kannagi
    Homme Profil pro
    cyber-paléontologue
    Inscrit en
    Mai 2010
    Messages
    3 226
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : cyber-paléontologue

    Informations forums :
    Inscription : Mai 2010
    Messages : 3 226
    Par défaut
    Alors, quand tu dis que ce code n'est pas valide pour toi, tu veux dire que tu n'écrirais pas ce code si c'était ton programme, mais que potentiellement il marche quand même ?
    C'est exactement ça , je l'écrirais jamais , mais le code marche.
    Après je te déconseille ce genre écriture.

    Pas sur de comprendre ton probleme de union mais :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    typedef union
    {
        char type[2];
        short word;
    } obj;
     
    obj o;
    o.word = 0;
    o.type[1] = 1;
    printf("%d\n",o.word); // affiche 256 donc ça marche bien
    ça fait ce que tu demande type[0] écrit sur le premier octet et type[1] sur le deuxième.
    J'ai mis short ,mait tu peux créer un type personnalisé avec la taille que tu veux.

  5. #5
    Membre actif
    Inscrit en
    Décembre 2009
    Messages
    95
    Détails du profil
    Informations forums :
    Inscription : Décembre 2009
    Messages : 95
    Par défaut
    Merci mais je suis désolé, probablement mon explication n'est pas clair car ce n'est pas ce que je souhaite.

    Actuellement, j'ai ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    typedef struct{
        uint16_t type;
        uint64_t word;
    } obj;
    Je traite l'entier word d'une certaine manière mais en réalité, c'est une mauvaise représentation. En effet, j'interdis à l'utilisateur de mon programme de rentrer des données supérieurs à 64 bits grosso modo. Et si l'utilisateur rentre des données sur 8 ou 9 bits, je les stocks dans mes entiers word de 64 bits mais du coup, je sous-utilise la mémoire. Car cette structure obj, je l'alloue potentiellement des milliards de fois.

    Ce que je voudrais, dans l'idéal, c'est :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    typedef struct{
        uint16_t type;
        uint8_t tab1[x];
        uint8_t tab2[y];
    } obj;
    x et y peuvent être n'importe quoi entre 1 et 1024 par exemple. Pour réaliser ce type de structure, on me conseillerait de faire :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    typedef struct{
        uint16_t type;
        uint8_t* tab1;
        uint8_t* tab2;
    } obj;
    Et d'allouer dynamiquement tab1 et tab2 a l'exécution de mon programme. Or on conviendra que si mon processeur est 64 bits, et que je ne souhaite allouer dans tab1 et tab2 que disons deux cases, je me retrouve à stocker deux pointeurs sur 64 bits pour seulement stocker 2x2 cases de 8 bits ...

    C'est pour cela que j'avais envisagé d'utiliser les macros avec l'opérateur ## :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    #define DECLARE_TAB(A,B)                           \
        typedef struct _LINE_##A##_##B                  \
        {                                               \
            uint8_t tab1[A];                            \
            uint8_t tab2[B];                         \
        } LINE_##A##_##B;
    Avec ceci, je peut lire mes données, décider que tab1 doit contenir 2 cellules et tab2 4 cellules. De ce fait, j'initialise le type LINE_2_4 qui définit un struct contenant un tableau tab1 de 2 cellules et un tableau tab2 de 4 cellules.

    J'aurais ensuite déclaré ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    #define DECLARE_OBJ(A,B)                             \
        typedef struct _OBJ                              \
        {                                               \
            uint16_t type;                              \
            LINE_##A##_##B obj;                   \
        } OBJ;
    OBJ serait en quelque sorte une enveloppe pour mon type dynamique dont le nom est fixe. L'idée est d'utiliser dans mon code qui sera compilé le type OBJ partout, et de préciser seulement à l'allocation d'un struct OBJ les valeurs de A et B pour l'allocation du type LINE_##A##_##B qui est situé dans OBJ.

    Or j'ai peur que cela ne soit pas possible car les "types" OBJ et LINE_##A##_##B n'existe qu'à l'exécution, mais le code est compilé d'abord et pour le compilateur, OBJ et LINE_##A##_##B n'existe pas (ou pas encore du moins ...). C'est ma déduction, je ne suis sur de rien, et j'aurais aimé avoir confirmation

    Je ne sais pas si je suis plus clair que dans mon premier message ou non.

  6. #6
    Membre actif
    Inscrit en
    Décembre 2009
    Messages
    95
    Détails du profil
    Informations forums :
    Inscription : Décembre 2009
    Messages : 95
    Par défaut
    En fait, c'est tout a fait possible d'utiliser le type "dynamique" OBJ déclaré en macro dans vos fonctions standard (pas écrite en macro), genre votre main(). Il faut juste ne pas être nounouille comme moi et oublier d'appeler ses define qui, eh bien qui définissent votre type "dynamique".

    Exemple :

    obj.h
    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
     
    #define DECLARE_TYPE(A,B)                           \
        typedef struct _LINE_##A##_##B                  \
        {                                               \
            uint8_t tab1[A];                            \
            uint8_t tab2[B];                         \
        } LINE_##A##_##B;                       \
        typedef struct _OBJ                              \
        {                                               \
            uint16_t type;                              \
            LINE_##A##_##B obj;                   \
        } OBJ;
     
    #define DECLARE_FUNCTION()                           \
        OBJ *CREATE_OBJ()                  \
        {                                               \
            return (OBJ*)malloc(sizeof(OBJ));                            \
        }                       \
    main.c

    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
     
    #include <stdio.h>
    #include <stdlib.h>
    #include <stdint.h>
    #include "inttypes.h"
     
    int main()
    {
        DECLARE_TYPE(1,2);
        DECLARE_FUNCTION();
        OBJ *truc = CREATE_OBJ();
        truc->type = 1;
        truc->container->tab2[1] = 128;
        printf("truc->type = %" PRIu16 "\n", truc->type);
        printf("truc->container->tab2[1] = %" PRIu8 "\n", truc->container->tab2[1]);
     
        return 0;
    }
    L'exécution de ce main affichera bien :

    truc->type = 1
    truc->container->tab2[1] = 128
    Tadaaaaaaaaam

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [Template] Question sur la programmation générique
    Par tlemcenvisit dans le forum C++
    Réponses: 4
    Dernier message: 03/11/2008, 11h51
  2. Sous-programmes génériques
    Par Tonio12 dans le forum Langages de programmation
    Réponses: 22
    Dernier message: 26/02/2007, 20h07
  3. [JDK-5.0]Programmation générique
    Par Bobo59 dans le forum Langage
    Réponses: 2
    Dernier message: 01/05/2005, 20h17
  4. [Programmation générique] template - iterator_traits
    Par Paul Atreide dans le forum Langage
    Réponses: 2
    Dernier message: 14/03/2005, 23h09

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