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 :

Problème de template (encore..)


Sujet :

C++

  1. #1
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2011
    Messages
    91
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Décembre 2011
    Messages : 91
    Points : 48
    Points
    48
    Par défaut Problème de template (encore..)
    Bonjour à tous,

    comme mentionner dans le titre j'ai un problème de template via un code qui m'a été donné sur ce forum (et que j'ai complété):

    j'ai une structure qui définit une variable :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    struct var
    {
    uint64_t val; //valeur de ma variable (oui je stock toujours les valeurs sur 64bits)
    unsigned int accessSize //taille de ma variable
    unsigned int address //adresse de la variable
    unsigned int msb //rang du msb
    unsigned int lsb //rang du lsb
    }
    Et une méthode template pour lire en mémoire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    ttemplate <class T>
    void read(T& val, const unsigned char* data, int msb, int lsb, bool big_endian=true)
    {
        const size_t size = sizeof(T);
        typedef typename unsigned_<size>::type type;
        type *ptr = reinterpret_cast<type*>(&val);
        for(size_t i=0; i<size; ++i)
            ptr[big_endian ? size-i-1: i] = data[i];
        val <<= (sizeof(val) * CHAR_BIT - msb - 1);
        val >>= lsb;
    }
    Avec cette méthode on lit de la taille du type qui contient la valeur de la variable et non de l'accessSize de la variable. J'ai donc essayé de refaire cette méthode template pour avoir ca :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    template <class T>
    void readn(T& val, const char* data, int msb, int lsb, int size, bool big_endian=true)
    {
        typedef typename unsigned_<size>::type type;
        type *ptr = reinterpret_cast<type*>(&val);
        for(size_t i = 0; i < size; ++i)
            ptr[big_endian ? size - i - 1 : i] = data[i];
        val <<= size * CHAR_BIT - msb - 1;
        val >>= lsb;
    }
    Mais j'ai eu une erreur de compilation ligne 4 (cannot appear in a constant-expression)
    Donc quelqu'un m'a dit de faire ca :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    template <class T, size_t SIZE>
    void readn(T& val, const char* data, int msb, int lsb, bool big_endian=true)
    {
        typedef typename unsigned_<SIZE>::type type;
        type *ptr = reinterpret_cast<type*>(&val);
        for(size_t i = 0; i < SIZE; ++i)
            ptr[big_endian ? SIZE - i - 1 : i] = data[i];
        val <<= SIZE * CHAR_BIT - msb - 1;
        val >>= lsb;
    }
    C'est cool ca compile ! Le probleme c'est que qu'on l'appelle 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
    int main()
    {
        unsigned char data[1];
        data[0] = 127;
     
        var variable;
        variable.val = 0;
        variable.accessSize = 1;
        variable.msb = 7;
        variable.lsb = 0;
        variable.address = 0;
        readn<uint64_t, 1/* EN DUR BERK*/>(variable.val, data, variable.msb, variable.lsb, true);
        return 0;
    }
    Mais moi je veux pas lire d'une taille écrite en dur mais d'une taille contenue dans une variable !
    Une genre de :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    readn<uint64_t>(variable.val, data, variable.msb, variable.lsb, variable.accessSize, true);
    //OU
    readn<uint64_t, variable.accessSize>(variable.val, data, variable.msb, variable.lsb, true);
    Si quelqu'un a une solution, ce serait sympa.
    Merci d'avance.

  2. #2
    Membre émérite

    Inscrit en
    Mai 2008
    Messages
    1 014
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 1 014
    Points : 2 252
    Points
    2 252
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    template <class T>
    void readn(T& val, const char* data, int msb, int lsb, int size, bool big_endian=true)
    {
        typedef typename unsigned_<size>::type type;
        char *ptr = reinterpret_cast<char*>(&val);
        for(size_t i = 0; i < size; ++i)
            ptr[big_endian ? size - i - 1 : i] = data[i];
        binary(val);
        val <<= size * CHAR_BIT - msb - 1;
        val >>= lsb;
    }
    A quoi sert la ligne 4 avec le typedef ? Tu ne l'utilises pas dans le reste de la fonction, autant la supprimer non ?

  3. #3
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Salut,

    Tu dois considérer que les paramètres template doivent obligatoirement être connus à la compilation.

    Tu peux transmettre, au moment de l'exécution, une valeur connue à la compilation comme argument à une fonction qui attend cette valeur, mais tu ne peux pas faire l'inverse.

    Ca, c'est pour l'explication "rapide" de la raison de ton erreur de compilation

    Ceci dit, pour éviter le recours à l'indication de la taille en dur, tu peux utiliser l'opérateur sizeof() qui renvoie une constante de compilation.

    Dans ton cas, tu pourrais donc t'en sortir avec un code proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    int main()
    {
        unsigned char data[1];
        data[0] = 127;
     
        var variable;
        variable.val = 0;
        variable.accessSize = 1;
        variable.msb = 7;
        variable.lsb = 0;
        variable.address = 0;
        writen<uint64_t, sizeof(uint64_t)>(variable.val, data, variable.msb, variable.lsb, true);
        return 0;
    }
    (Tiens, tu as remarqué?? tu donne le code de readn mais tu essayes d'utiliser writen... enfin, le principe reste le meme )Mais il y a encore mieux à faire...

    En effet, la taille du type qui spécifie T dépend directement... du type qui spécifie T, c'est fou, ca, non

    Depuis C++11, il est possible de fournir une valeur par défaut pour les paramètres template des fonctions (en respectant la même règle que pour les valeurs par défaut des paramètres des fonctions), ce qui te permettrait, si tu profites déjà de C++11 d'avoir un code proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    template <class T, size_t SIZE=sizeof(T)>
    void readn(T& val, const char* data, int msb, int lsb, bool big_endian=true)
    {
        typedef typename unsigned_<SIZE>::type type;
        char *ptr = reinterpret_cast<char*>(&val);
        for(size_t i = 0; i < SIZE; ++i)
            ptr[big_endian ? SIZE - i - 1 : i] = data[i];
        binary(val);
        val <<= SIZE * CHAR_BIT - msb - 1;
        val >>= lsb;
    }
    Mais si tu ne profites pas encore des bienfaits de C++11, il te reste une autre solution, qui est, sommes toutes, tout aussi simpe: utiliser l'opérateur sizeof pour définir une valeur statique constante directement dans le corps de ta fonction.

    De toutes manières, étant donné que tu auras autant d'implémentation de la fonction que de type utilisé pour spécialiser T, cela ne posera aucun problème

    Cela donnerait donc quelque chose comme
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    template <class T>//oui, je retire SIZE des paramètres template
    void readn(T& val, const char* data, int msb, int lsb, bool big_endian=true)
    {
        static const size_t SIZE= sizeof(T);
        typedef typename unsigned_<SIZE>::type type;
        char *ptr = reinterpret_cast<char*>(&val);
        for(size_t i = 0; i < SIZE; ++i)
            ptr[big_endian ? SIZE - i - 1 : i] = data[i];
        binary(val);
        val <<= SIZE * CHAR_BIT - msb - 1;
        val >>= lsb;
    }
    Ceci dit, je ne saurais que t'inciter à envisager la création d'un foncteur (ou plutôt d'un helper qui fournirait les deux fonctions readn et writen) pour ce boulot, plutot que de garder les fonction libres.

    De manière générale, cela apporte beaucoup plus de souplesse à l'utilisation et te permettrait de n'avoir pas à passer systématiquement tous ces paramètres
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  4. #4
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2011
    Messages
    91
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Décembre 2011
    Messages : 91
    Points : 48
    Points
    48
    Par défaut
    Désolé Arzar et koala01 pour les coquilles dans mon code que j'ai tout de suite édité, on va mettre cela sous le compte de la chaleur hein et merci pour vos réponses.

    Juste koala01, je ne crois pas que tu as saisis mon problème (ou c'est qu'il n'y a pas de solution ).

    Mon type T peut être un int64_t, un uint64_t ou un double car stocke mes valeurs sur 64bits (access size maximale autorisée dans le programme) mais c'est pas parce que sizeof(T) = 8 octets que ma variable fait 8 octets ! Sa valeur est contenue dans 8octets mais sa taille est définie par la variable "accessSize" ! Et je veux pouvoir lire et écrire de cette taille la

  5. #5
    Membre éprouvé
    Inscrit en
    Avril 2005
    Messages
    1 110
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 1 110
    Points : 937
    Points
    937
    Par défaut
    Citation Envoyé par DarKaa Voir le message
    ou c'est qu'il n'y a pas de solution
    C'est à craindre...
    Il faut pouvoir "énumérer" d'une manière ou d'une autre les différentes valeurs possibles de ta variable accessSize dès la compilation.
    J'ai un problème semblable en attente de solution élégante.
    Provisoirement je m'en tire avec un code comme ceci:
    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
    void TableRun(const std::string & outputDir, const char *tablename,
    	const char *fields, unsigned _Nsort, unsigned _Nsearch)
    {
    		GenericFmt gf;
    		gf.Init(outputDir,tablename);
    		if (1==_Nsort)
    		{
    			DirectIndexFixKey<1>(gf, fields, _Nsearch);
    		}
    		else if (2==_Nsort)
    		{
    			DirectIndexFixKey<2>(gf, fields, _Nsearch);
    		}
    		else if (3==_Nsort)
    		{
    			DirectIndexFixKey<3>(gf, fields, _Nsearch);
    		}
    		else if (4==_Nsort)
    		{
    			DirectIndexFixKey<4>(gf, fields, _Nsearch);
    		}
    		else
    			throw std::runtime_error("TableRun() unsupported _Nsort, extend code");
    }

  6. #6
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Citation Envoyé par DarKaa Voir le message
    Désolé Arzar et koala01 pour les coquilles dans mon code que j'ai tout de suite édité, on va mettre cela sous le compte de la chaleur hein et merci pour vos réponses.

    Juste koala01, je ne crois pas que tu as saisis mon problème (ou c'est qu'il n'y a pas de solution ).

    Mon type T peut être un int64_t, un uint64_t ou un double car stocke mes valeurs sur 64bits (access size maximale autorisée dans le programme) mais c'est pas parce que sizeof(T) = 8 octets que ma variable fait 8 octets ! Sa valeur est contenue dans 8octets mais sa taille est définie par la variable "accessSize" ! Et je veux pouvoir lire et écrire de cette taille la
    Ah, au temps pour moi, je ne l'avais pas compris comme cela...

    Ben, dans ce cas, c'est ta structure "var" que tu dois rendre template :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    template <SIZE>
    struct var
    {
    uint64_t val; //valeur de ma variable (oui je stock toujours les valeurs sur 64bits)
    enum{ accessSize = SIZE}; //taille de ma variable
    unsigned int address, //adresse de la variable
    unsigned int msb, //rang du msb
    unsigned int lsb, //rang du lsb
    };
    ou
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    template <typename TYPE>
    struct var
    {
    typedef value_type TYPE;
    uint64_t val; //valeur de ma variable (oui je stock toujours les valeurs sur 64bits)
    enum{ accessSize = sizeof(value_type)}; //taille de ma variable
    unsigned int address, //adresse de la variable
    unsigned int msb, //rang du msb
    unsigned int lsb, //rang du lsb
    };
    qui seront utilisées sous une forme proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    template <class T>
    void readn(T& val, const char* data, int msb, int lsb, bool big_endian=true)
    {
        typedef var<sizeof(T)> var_type;
        char *ptr = reinterpret_cast<char*>(&val);
        for(size_t i = 0; i < var_type::accessSize; ++i)
            ptr[big_endian ? SIZE - i - 1 : i] = data[i];
        binary(val);
        val <<= SIZE * CHAR_BIT - msb - 1;
        val >>= lsb;
    }
    ou de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    template <class T>
    void readn(T& val, const char* data, int msb, int lsb, bool big_endian=true)
    {
        typedef var<T> var_type;
        char *ptr = reinterpret_cast<char*>(&val);
        for(size_t i = 0; i < var_type::accessSize; ++i)
            ptr[big_endian ? SIZE - i - 1 : i] = data[i];
        binary(val);
        val <<= SIZE * CHAR_BIT - msb - 1;
        val >>= lsb;
    }
    selon le choix que tu auras fait

    [EDIT]Je préférerais personnellement la deuxième solution, car elle apporte une information supplémentaire par rapport à la première: le type de la donnée que tu manipule.

    Cela te permettra, "ailleurs", le type de la donnée d'origine en cas de besoin
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  7. #7
    Membre éprouvé
    Inscrit en
    Avril 2005
    Messages
    1 110
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 1 110
    Points : 937
    Points
    937
    Par défaut
    Pour 1), ça ne change pas le pb initial de DarKaa, à savoir qu'il ne peut pas faire:
    si accessSize est une variable et non une constante connue à la compil.

    Je pense que DarKaa ne veut/peut pas faire ceci:
    Pour 2), à lui de dire si ça lui va. Mais si j'ai bien compris, accessSize aura une valeur de 1 à 8 non connue à la compil.

  8. #8
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    En fait, le principe est bon, mais je me suis gouru au niveau de la fonction en elle-même...

    Il faut ajouter un deuxième paramètre template qui permette de faire varier le type de donnée à manipuler, sous une forme proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    template <typename T, typename U>
    void readn(T& val, const char* data, int msb, int lsb, bool big_endian=true)
    {
        typedef var<sizeof(U)> var_type;
        char *ptr = reinterpret_cast<char*>(&val);
        for(size_t i = 0; i < var_type::accessSize; ++i)
            ptr[big_endian ? SIZE - i - 1 : i] = data[i];
        binary(val);
        val <<= SIZE * CHAR_BIT - msb - 1;
        val >>= lsb;
    }
    ou de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    template <typename T, typename U>
    void readn(T& val, const char* data, int msb, int lsb, bool big_endian=true)
    {
        typedef var<U> var_type;
        char *ptr = reinterpret_cast<char*>(&val);
        for(size_t i = 0; i < var_type::accessSize; ++i)
            ptr[big_endian ? SIZE - i - 1 : i] = data[i];
        binary(val);
        val <<= SIZE * CHAR_BIT - msb - 1;
        val >>= lsb;
    }
    selon la solution envisagée pour rendre var template.

    A partir de là, tu pourras donc décider "tout simplement" d'appeler cette fonction sous la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    int main()
    {
        readn<uint64_t, char>(variable.val, data, variable.msb, variable.lsb, true); // un byte effectif
        readn<uint64_t, unsigned long long>(variable.val, data, variable.msb, variable.lsb, true); // 8 bytes effectifs
        return 0;
    }
    car sizeof renvoie une constante de compilation qui correspond à la taille (en nombre de byte) du type indiqué et que les valeurs énumérées sont, elles-même des constantes de compilation.

    Mais le principe que j'ai énoncé au niveau de la structure var est tout à fait correct car il permet de fournir une constante de compilation pour accessSize
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  9. #9
    Expert confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2012
    Messages
    1 711
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2012
    Messages : 1 711
    Points : 4 442
    Points
    4 442
    Par défaut
    Hello,

    si tu lis toujours tes données dans des uint64, pourquoi avoir besoin de template ?

    Quelque chose comme ça ne suffirait pas ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    void readn(const char* data, var& v, bool big_endian=true) {
        assert(v.accessSize <= sizeof(uint64_t));
        v.val = 0;
        unsigned char *ptr = reinterpret_cast<unsigned char*>(&v.val);
        for(size_t i = 0; i < v.accessSize; ++i) {
            ptr[big_endian ? v.accessSize - i - 1 : i] = data[v.address + i];
        }
        v.val <<= v.accessSize* CHAR_BIT - v.msb - 1;
        v.val >>= v.lsb;
    }
     
    var variable = { /* ... */ };
    readn(data, variable);
    Pas pu tester le code, aucune idée de ce que sont lsb et msb, donc je sais pas quel résultat attendre.

  10. #10
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2011
    Messages
    91
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Décembre 2011
    Messages : 91
    Points : 48
    Points
    48
    Par défaut
    Merci à tous de répondre et proposer des idées tout d'abord

    Comme camboui l'a très bien dis ce que je veux c'est pouvoir faire ça avec la première solution de koala01:
    et surtout pas Ensuite pour la deuxième solution de koala01, je ne doute pas qu'elle fonctionne mais rien qu'en appelant la méthode readn j'ai des doutes.. Comme je l'ai déja dis je n'ai que les variables (uint64_t, int64_t ou double) val, unsigned accessSize, unsigned int address, unsigned int msb, unsigned int lsb alors comment arriver à cela :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    readn<uint64_t, char>(variable.val, data, variable.msb, variable.lsb, true);
    sans une batterie de if sur l'accessSize?

    Donc je pense faire comme camboui me l'a suggéré, faire la batterie de if sur l'acessSize pour appeler readn<1 ou 2 ou 4 ou 8>

    Pour répondre à Iradrille, les types ne sont pas que des uint64_t, (hélas et heureusement d'ailleurs car si j'arrivais pas à faire cette méthode avec UN type fixe, ce serait grave )

  11. #11
    Membre éprouvé
    Inscrit en
    Avril 2005
    Messages
    1 110
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 1 110
    Points : 937
    Points
    937
    Par défaut
    Pour savoir, elle fait quoi ta fonction ?
    On dirait une fonction de (dé)sérialization.

    Sinon je crois avoir compris ce qu'il te faut, mais j'ai besoin d'exemples d'appel à ta fonction readn<T> en donnant des types différents pour le paramètre template T.

  12. #12
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Citation Envoyé par DarKaa Voir le message
    Merci à tous de répondre et proposer des idées tout d'abord

    Comme camboui l'a très bien dis ce que je veux c'est pouvoir faire ça avec la première solution de koala01:
    et surtout pas Ensuite pour la deuxième solution de koala01, je ne doute pas qu'elle fonctionne mais rien qu'en appelant la méthode readn j'ai des doutes..
    Tu ne devrais pourtant pas
    Comme je l'ai déja dis je n'ai que les variables (uint64_t, int64_t ou double) val, unsigned accessSize, unsigned int address, unsigned int msb, unsigned int lsb alors comment arriver à cela :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    readn<uint64_t, char>(variable.val, data, variable.msb, variable.lsb, true);
    sans une batterie de if sur l'accessSize?
    Parce que l'opérateur sizeof (que j'utilise à chaque fois) renvoie la taille du type que l'on passe en paramètre sous la forme d'une constante de compilation, autrement dit, qui est parfaitement connue du compilateur lorsqu'on l'utilise, et qui peut donc parfaitement intervenir dans le cadre d'un paramètre template et qu'il en va de même pour les valeurs énumérées.

    C'est dans cette optique que les trois premières choses que j'ai faites ont été:
    1. de rendre var template avec un paramètre template correspondant au type de la donnée manipulée
    2. de transformer accessSize en valeur énumérée
    3. de donner à accessSize la valeur (connue à la compilation) correspondant à la taille (en nombre de bytes) du type de donnée manipulée

    Il faut savoir que le compilateur a besoin de pouvoir déterminer clairement quelle taille chaque type va prendre en mémoire, ce qui explique que sizeof fournisse des constantes de compilation.

    au final, tu auras sans doute des résultats identique pour (unsigned) int et pour (unsigned) long, mais c'est parce que l'on se rend compte, à l'usage, que la taille d'un long est souvent identique à celle d'un int, bien qu'on ne puisse en aucun cas partir de cette hypothèse dans nos raisonnements (car la norme dit que sizeof(char)=1 et que sizeof(char)<=sizeof(short)<=sizeof(int)<=sizeof(long)<=sizeof(long long) )
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  13. #13
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2011
    Messages
    91
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Décembre 2011
    Messages : 91
    Points : 48
    Points
    48
    Par défaut
    Au cas où j'aurai pas posté assez de message à l'aide sur ce forum depuis qq mois , je vais réexpliquer mon but.

    J'essaye de créer un éditeur de base de données binaire. J'en suis au stade ou un utilisateur crée un MCD (pour décrypter la librairie) ou il crée des tables (pour l'instant je crée souvent une table) et des données dans ces (cette) table.
    Les données ont pleins d'attributs que je stocke biensurs dans des variables (un type(entier, entier signé, booleen, enumératif, ascii), adresse dans la librairie, valeur, taille d'accès (1, 2, 4 ou 8), rang lsb, rand msb et j'en passe).

    Peut importe ce que l'utilisateur renseigne dans l'acessSize j'ai stocké la valeur dans 64bits. (Je me suis dit "j'ai toute ma donnée et au moment de l'écrire ou la lire je le ferai de la taille souhaitée. Peut être aurai je pas du )

    Nous voila à l'étape ou j'alloue un tableau de char ou unsigned char de la taille de la somme de toutes les accessSize. Et hop, j'écris et je lis (enfin j'aimerai)
    Donc je voyais ça comme ça:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    char ou unsigned char *data; //alloué et memseté de la bonne taille
    TableaDeVar tab;
    unsigned int i = 0
    while (i < tab.size())
    {
    readn(VALEUR, data + ADRESSE, ACCESSSIZE, LSB, MSB, ENDIANITE); // Biensur c'est cette ligne qui pose problème et dont je n'ai aucune idée de comment tourner ça..
    ++i;
    }

  14. #14
    Expert confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2012
    Messages
    1 711
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2012
    Messages : 1 711
    Points : 4 442
    Points
    4 442
    Par défaut
    Citation Envoyé par DarKaa Voir le message
    Pour répondre à Iradrille, les types ne sont pas que des uint64_t, (hélas et heureusement d'ailleurs car si j'arrivais pas à faire cette méthode avec UN type fixe, ce serait grave )
    Ça ne change rien au problème : cette taille n'a pas besoin d'être template, elle sert juste dans la boucle.

    Quelque chose comme ça
    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
    template <class T>
    struct var {
    	static_assert(sizeof(T) == 8, "64bits type required"); // il y a moyen d'etre plus restritif si besoin
    	T val; //valeur de ma variable (oui je stock toujours les valeurs sur 64bits)
    	unsigned int accessSize //taille de ma variable
    	unsigned int address //adresse de la variable
    	unsigned int msb //rang du msb
    	unsigned int lsb //rang du lsb
    }
     
    template <class T>
    void readn(const unsigned char* data, T& v, bool big_endian=true) {
    	assert(v.accessSize <= sizeof(v.val));
    	unsigned char *bytePtr = reinterpret_cast<unsigned char*>(&v.val);
    	uint64_t *uint64Ptr = reinterpret_cast<uint64_t*>(&v.val);
     
    	*uint64Ptr = 0;
    	for(size_t i = 0; i < v.accessSize; ++i) {
    		bytePtr[big_endian ? v.accessSize - i - 1 : i] = data[v.address + i];
    	}
    	(*uint64Ptr) <<= v.accessSize* CHAR_BIT - v.msb - 1;
    	(*uint64Ptr) >>= v.lsb;
    }
     
    var<double> vDouble = { /* ... */ };
    var<uint64_t> vUint64 = { /* ... */ };
     
    readn(data, vDouble);
    readn(data, vUint64);
    Le but est bien de lire accessSize octets dans data et me stocker ça dans val (qui peut être de n'importe quel type, sur 64 bits) ?

  15. #15
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Si tu veux bien, je voudrais qu'on soit sur de parler de la même chose, et donc essayer de paraphraser ce que tu expliques

    Tu as une structure, pour l'instant, qui (une fois qu'on en a retiré les "parasites" pour la compréhension) ressemble à
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    struct Data{
        uint64_t value; // la représentation binaire de la donnée, doffice sur 84 bits
        unsigned int accessSize; // le nombre de bits réellement occupés par la données (8 bits pour un char, 16 pour un short, 32 pour un int, ...
    };
    Jusque là, nous sommes d'accord

    Le problème auquel tu est confronté, c'est qu'il faut savoir combien de bytes doivent être pris en compte au moment de la lecture ou de l'écriture, nous sommes bien d'accord

    Et tu voudrais, enfin, que l'utilisateur n'aie pas à indiquer explicitement la taille qui doit être utilisée pour la donnée que tu veux manipuler.

    Jusque là, nous sommes toujours bien d'accord

    La solution à ton problème passe, en gros, par un opérateur qui est capable de founrir lors de la compilation la taille réelle de la valeur que tu veux écrire en fonction du type particulier de cette valeur: l'opérateur sizeof( identifiantDeType).

    Comme je te l'ai dit plus haut, le compilateur doit, de toutes manières, connaitre systématiquement l'espace mémoire occupé par n'importe quel type qu'il rencontre, ne serait-ce que pour avoir la certitude, si tu déclares deux variables de types différents (ou non, d'ailleurs) de manière successive, que la deuxième variable n'ira pas "empiéter" sur une case mémoire qui serait utilisée par la première!

    Ca la foutrais en effet plutôt mal si, avec un code proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    int main(){
       A a; // on se fout pas mal du type de A et de B ici, c'est juste pour 
       B b; // l'exemple :D
       b.membre= nouvelleValeur; // de meme que du type de B::membre :D
    }
    tu te retrouverais avec une valeur différente pour l'un de membres de l'objet a

    De plus, une fois que la taille prise en mémoire par un type donné est connue, il n'y a plus de raison qu'elle change (du moins, sans modifier le corps du type en question), autrement, on risquerait encore bien de se retrouver dans cette situation ubuesque : une fois que le compilateur a croisé la définition d'une classe ou d'une structure, il peut donc considérer le nombre de bytes nécessaire à la représentation en mémoire de cette classe ou de cette structure comme une constante de compilation, et c'est ce qu'il fait.

    Pour les types primtifs (char, short, int, long, long long (si disponible), float, double, long double (si disponible) et leurs variante unsigned (si elles existent), ces tailles sont d'ailleurs dépendante de l'implémentation et de l'architecture.

    Ce qui fait que, si tu ne peux jamais savoir, sans avoir utilisé sizeof (ou sans avoir été voir directement dans les entrailles des fichiers d'en-tête) quel sera la taille d'un type primitif (hormis char, qui a d'office une taille de 1), tu as, en tout état de cause, la certitude que cette taille sera, d'office, toujours identique pour une architecture donnée, et que, quelle que soit cette taille, ce sera toujours "un multiple de 1"

    Tu ne pourras, en effet, jamais te retrouver avec un type quel qu'il soit qui aurait une taille de, mettons, 3.5, c'est strictement illégal

    Il existe une autre possibilité d'avoir une valeur (numérique entière) qui puisse être considérée comme une constante de compilation: les valeurs énumérées (comprend: les identifiant que tu places dans les énumérations).

    Par défaut, la première valeur énumérée que l'on trouve dans une enum est 0 et la valeur des suivantes est toujours égale à celle de la valeur énumérée qui précède +1:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    enum myEnum{
        zero, // par défaut, vaut 0
        one, // par défaut, vaut 1 (0+1)
        two, // par défaut, vaut 2 (1+1)
        three, // par défaut, vaut 3 (2+1)
        four, // par défaut, vaut 4 (3+1)
        five, // par défaut, vaut 5 (4+1)
    };
    Mais il est aussi possible d'imposer une valeur particulière pour n'importe quelle valeur énumérée. Dans ce ca, la valeur énumérée suivante suivra simplement la règle de base, mais en se basant sur la valeur que l'on a imposée:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    enum myEnum{
        truc, // par défaut, vaut 0
        brol=10, // vaut... 10 et non 1
        bidule,  // vaut... 10+1 (11)
        machin // vaut 11+1
    };
    Ici aussi, les valeurs sont considérées comme des constantes de compilation (d'ailleurs, c'est bien simple: dans le code binaire, ce sont les valeurs "finales" qui sont utilisée, même si on rajoute quelques informations pour le débuggeur en mode debug ), parce que le seul moyen pour changer la valeur de machin pour lui faire valoir 24 par exemple serait... de modifier directement le code source de l'énumération, ce qui ne peut évidemment pas se faire durant le cycle de compilation

    En plus, il faut te dire que, meme si tu envisages une formule biscornue pour arriver à forcer la valeur d'une valeur énumérée (on aurait pu écrire quelque chose comme machin = (brol*bidule/2)%5, cela aurait encore parfaitement été ) la valeur utilisée pour brol est une valeur littérale (comprend une valeur écrite en dure dans le code), ce qui fait que la valeur de bidule (qui est égale à celle de de brol +1) peut aussi être considérée comme une valeur constante, ce qui fait que, au final, nous n'aurions que des valeurs constantes à manipuler pour obtenir le résultat: (10*11/2)%5 = (110/2)%5 = 55%5 = ... 0(c'était pas fait expres, je le jure ).

    On a donc, d'un coté, la possibilité de récupérer la taille d'un type donné sous la forme d'une valeur constante -- mieux, d'une constante de compilation -- et de l'autre la possibilité celle de définir un symbole utilisable pour représenter une constante de compilation...

    C'est deux possibilités sont faites pour vivre ensemble, non

    Utilisons donc l'une (la valeur énumérée) pour identifier clairement l'autre (la taille du type), et nous pourrons sans aucun problème utiliser la valeur énumérée partout où l'on peut en avoir besoin.

    Mieux encore: Si l'on a deux structure différentes qui disposent toutes les deux d'une valeur énumérée portant le même identifiant (bien que de manière différente, merci les règles de portées ), nous pourrons utiliser ces deux structures indifféremment comme spécification d'un template:
    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
    struct Schar{
        enum{value = sizeof(char)};
    };
    struct SFloat{
        enum {value = sizeof(float)};
    };
    template <typename T>
    void foo(T const & t){
        std::cout<<t.value<<std::endl;
    }
     
    template <typename T>
    void bar(){
        std::cout<<"même pas besoin d'une instance de T:"<<T::value<<std::endl;
    }
    int main(){
        Schar sc;
        SFloat sf;
        /* merci la déduction de  type */
        foo(sc);      // sortie 1
        foo(sf);      // sortie 4
        bar<Schar>(); // sortie 1
        bar<SFloat>();//sortie 4
    }
    Sauf que, si tu veux le faire de la sorte, tu es bon pour créer 15 structures différentes rien que pour les types primitifs, et je ne parle même pas des types personnalisés pour lesquels tu voudrais pouvoir travailler de la sorte... DRY (principe d'eXtrem Programming, je te l'accorde) en prend un sérieux coup sur la patate

    C'est d'autant plus dommage que le seul point de variation correspond finalement au type de donnée que l'on donne à sizeof et que l'on dispose d'un moyen idéal pour permettre la variation d'un type dont on sait pertinemment comment il sera manipulé: le paradigme générique.

    Nous pourrions donc nous "contenter" d'écrire une seule fois le code, et de laisser le compilateur se débrouiller pour la suite:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    template <typename T>
    struct TS{
        enum{value = sizeof(T)};
    };
    et en modifiant un tout petit peu les fonctions sous la forme de
    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
     
    template <typename T>
    void foo(TS<T> const & t){
        std::cout<<t.value<<std::endl;
    }
     
    template <typename T>
    void bar(){
        std::cout<<"même pas besoin d'une instance de T:"<<TS<T>::value<<std::endl;
    }
    int main(){
        TS<char> tc;
        TS<float> tf;
        /* merci la déduction de  type */
        foo(tc);      // sortie 1
        foo(tf);      // sortie 4
        bar<char>(); // sortie 1
        bar<float>();//sortie 4
    }
    ca marche de nouveau.

    Mieux, encore! Si tu crées une structure perso proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    /* je la fais expressément sous cette forme, pour que la taille
     * ne fasse aucun doute (c'est la somme des deux membres :D
     */
    struct personne{
        char nom[15];
        char prenom[15];
    };
    tu pourras parfaitement écrire ta fonction main sous la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    int main(){
        TS<personne> tp;
        /* merci la déduction de  type */
        foo(tp);      // sortie 30
        bar<personne>(); // sortie 30
    }
    et ca fonctionnera encore

    Et, pour te montrer que cela fonctionne parfaitement, une dernière petite fonction qui écrit en boucle:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    template <typename T>
    void loop(){
        std::cout<<"i will loop "<<TS<T>::value<<" times :"<<std::endl;
        for(int i=0;i< TS<T>::value; ++i){
            std::cout<< i<<" ";
       }
       std::cout<<std::endl;
    }
     
    int main(){
        loop<char>(); // (0)
        loop<float>();  // (0...3)
        loop<personne>(); //(0...29)
    }
    C'est pas magique ca

    Maintenant, tu n'as plus qu'à changer l'identifiant value de ma classe TS par l'identifiant accessSize d'une classe template similaire à ta structure var, et le tour est joué
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  16. #16
    Membre éprouvé
    Inscrit en
    Avril 2005
    Messages
    1 110
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 1 110
    Points : 937
    Points
    937
    Par défaut
    Citation Envoyé par DarKaa Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    char ou unsigned char *data; //alloué et memseté de la bonne taille
    TableauDeVar tab;
    unsigned int i = 0
    while (i < tab.size())
    {
    ... il manque du code ici:
    ... type de VALEUR ?
    ... type et initialization de ACCESSSIZE ? D'où vient sa valeur ?
        Est-elle déductible à la compil, ou bien vient-elle d'un fichier/db externe ?
    readn(VALEUR, data + ADRESSE, ACCESSSIZE, LSB, MSB, ENDIANITE); // Biensur c'est cette ligne qui pose problème et dont je n'ai aucune idée de comment tourner ça..
    ++i;
    }
    Pourrions-nous aussi avoir la définition complète de la structure/classe unsigned_<> ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    typedef typename unsigned_<SIZE>::type type;
    EDIT: Aaah... Bon, je suis en train de lire les autres sujets de DarKaa, voilà que je les découvre

  17. #17
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2011
    Messages
    91
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Décembre 2011
    Messages : 91
    Points : 48
    Points
    48
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Tu as une structure, pour l'instant, qui (une fois qu'on en a retiré les "parasites" pour la compréhension) ressemble à
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    struct Data{
        uint64_t value; // la représentation binaire de la donnée, doffice sur 84 bits
        unsigned int accessSize; // le nombre de bits réellement occupés par la données (8 bits pour un char, 16 pour un short, 32 pour un int, ...
    };
    Jusque là, nous sommes d'accord
    En fait, c'est pas tout à fait ça, c'est plutôt comme cela :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    union Type
    {
      uint64_t tUInt;
      int64_t  tInt;
      double   tDouble;
      char     *tChar;
    };
    struct Data{
        Type value; 
        unsigned int accessSize;
    };
    J'ai été obligé de faire ça car quand l'utilisateur crée une variable, il définit un type et je vois pas comment de pouvais faire tenir tous les types proposés dans une seul type informatique !
    Citation Envoyé par koala01 Voir le message
    Le problème auquel tu est confronté, c'est qu'il faut savoir combien de bytes doivent être pris en compte au moment de la lecture ou de l'écriture, nous sommes bien d'accord
    J'ai stocké la valeur de la variable sur 8 bytes mais cela ne veut pas dire que la variable a une taille de 8 bytes. Donc oui
    Citation Envoyé par koala01 Voir le message
    Et tu voudrais, enfin, que l'utilisateur n'aie pas à indiquer explicitement la taille qui doit être utilisée pour la donnée que tu veux manipuler.

    Jusque là, nous sommes toujours bien d'accord
    L'utilisateur renseigne toutes les données citées précédemment (à savoir: le type de la donnée qu'il souhaite créer, sa valeur, sa taille, son rang lsb et msb, sa valeur min et max, etc..), moi j'ai stocké tout ça dans une structure, j'ai un espace mémoire alloué de la bonne taille (char*) et je dois tout mettre à la bonne place ! Pouvoir consulter et modifier !
    En espérant avoir répondu

    Maintenant si j'ai bien compris, il faut que ce soit ma structure qui soit template et que ma fonction readn prenne non plus la valeur de la variable à créer mais la structure entière contenant toutes les infos sur la variable à créer. Et que le type template de ma variable soit définit au moment ou l'utilisateur crée la variable. Facon habile de contourner le problème

  18. #18
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Citation Envoyé par DarKaa Voir le message
    En fait, c'est pas tout à fait ça, c'est plutôt comme cela :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    Enum Type
    {
      uint64_t tUInt;
      int64_t  tInt;
      double   tDouble;
      char     *tChar;
    };
    struct Data{
        Type value; 
        unsigned int accessSize;
    };
    Elle a vraiment une drole de gueule ton énumération...

    J'espère que ce n'est pas ce que tu as fait
    J'ai été obligé de faire ça car quand l'utilisateur crée une variable, il définit un type et je vois pas comment de pouvais faire tenir tous les types proposés dans une seul type informatique !
    Ca, j'ai compris... Ce qui importe surtout, c'est que tu puisse déterminer, le plus tot possible, le type de la donnée et sa taille en mémoire!

    Le fait est que, comme je te l'ai (j'espère) clairement expliqué plus tôt, la taille de n'importe quel type que l'utilisateur pourrait créer est connue à la compilation

    J'ai stocké la valeur de la variable sur 8 bytes mais cela ne veut pas dire que la variable a une taille de 8 bytes. Donc oui
    Tu aurais pu stocker la valeur de la variable sur 168 bytes, le principe aurait été strictement le même, ce qui importe, c'est que tu sois d'accord avec mon assertion

    L'utilisateur renseigne toutes les données citées précédemment (à savoir: le type de la donnée qu'il souhaite créer, sa valeur, sa taille,
    Ce sont surtout ces deux points qui m'intéressent
    son rang lsb et msb, sa valeur min et max, etc..),
    et ceux là, même s'ils ont clairement un intérêt business, restent malgré tout des "parasites" qui empêchent la bonne compréhension du problème
    moi j'ai stocké tout ça dans une structure,
    Et tu as bien fait... Parce ce que toutes ces informations sont faites pour "travailler ensembles"

    Mais, cela implique aussi que tu aurais, de toutes manières, largement intérêt à transmettre cette structure à tes fonctions, plutôt que d'essayer de transmettre toutes les informations de manière séparées.

    En essayant de transmettre les informations de manière séparée, tu "défais" en quelque sorte ce que tu as fait en créant ta structure, et tu vas donc, en quelque sorte, à l'encontre même du but poursuivi par cette structure
    j'ai un espace mémoire alloué de la bonne taille (char*) et je dois tout mettre à la bonne place ! Pouvoir consulter et modifier !
    Mais qui est de taille fixe et qui correspond, quoi qu'il arrive, à la taille de 8bytes.

    Tu peux donc parfaitement rajouter un tableau statique de 8 char dans ta structure finalement, ce n'est jamais qu'une "autre représentation" de l'ensemble des informations contenues dans ta structure
    Maintenant si j'ai bien compris, il faut que ce soit ma structure qui soit template et que ma fonction readn prenne non plus la valeur de la variable à créer mais la structure entière contenant toutes les infos sur la variable à créer.
    De toutes manières, à partir du moment où ta fonction a besoin de toutes les informations (ou peu s'en faut) qui sont accessibles dans ta structure, il est beaucoup plus facile de transmettre directement la structure elle-même: tu limites le nombre de paramètres à fournir et donc le risque d'erreur au moment de le faire
    Et que le type template de ma variable soit définit au moment ou l'utilisateur crée la variable.
    C'est bien cela
    Facon habile de contourner le problème
    Attention, ce n'est pas une facon habile de contourner le problème!!! C'est une façon de faire qui ne présente que des avantages, dans le sens où, en transmettant ta structure, tu es sur de fournir d'office toutes les informations (et peut etre meme un peu plus, mais, quelle importance ) qui seront utiles et nécessaires à ta fonction, en étant sur de ne pas intervertir l'ordre dans lequel ces informations doivent être transmises (imagines la pagaille que tu risques d'avoir si, en transmettant toutes les informations une à une, tu venais à intervertir le rang lsb et le rang msb, voire les valeurs minimales et maximales )

    De plus, tu as, de toutes façons, créé une structure... Autant qu'elle serve chaque fois que possible, non
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  19. #19
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2011
    Messages
    91
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Décembre 2011
    Messages : 91
    Points : 48
    Points
    48
    Par défaut
    Pardonnez moi j'étais pas réveillé ! C'est une UNION et j'ai édité mon message !

  20. #20
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Citation Envoyé par DarKaa Voir le message
    Pardonnez moi j'étais pas réveillé ! C'est une UNION et j'ai édité mon message !
    Même une union, dans ces circonstances, c'est horrible, surtout au niveau de tChar (qui devrait plutôt être du genre de char tChar[8], car, autrement, tu vas avoir un problème).

    Et bon, comme le paradigme générique permet de faire quelque chose de correct et de simple, autant en profiter
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. Problème de session (encore)
    Par akapando dans le forum Langage
    Réponses: 2
    Dernier message: 23/05/2006, 16h54
  2. [xslt][Javascript] Problème de templates
    Par Dnallabar dans le forum XSL/XSLT/XPATH
    Réponses: 2
    Dernier message: 03/11/2005, 11h55
  3. problème classes templates...
    Par youp_db dans le forum C++
    Réponses: 3
    Dernier message: 02/11/2005, 13h04
  4. Réponses: 3
    Dernier message: 22/03/2005, 09h13

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