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

Langage C++ Discussion :

bitfield anonyme plus large que son type ?


Sujet :

Langage C++

  1. #1
    Membre actif
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2009
    Messages
    219
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France

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

    Informations forums :
    Inscription : Juin 2009
    Messages : 219
    Points : 239
    Points
    239
    Par défaut bitfield anonyme plus large que son type ?
    [excusez moi, clavier US]

    Bonjour a tous,

    Je travaille sur la realisation d'une bibliotheque de mathematique vectoriel pour simplifier les ecritures des calculs, et j'utilise des bitfields anonymes dans des templates de strutures dont le type est determiner en meta programing pour sauter un nombre d'octet bien precis dans une structure. Je m'explique ...

    Ici ce trouve la partie meta programming, simplement pour determiner un type integer a partir de son sizeof :
    github - /src/cmath_typedefs.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
     
        template <int ADDRESS_SIZE>
        struct MetaTypedef
        {
            typedef int32_t intX_t;
            typedef uint32_t uintX_t;
            typedef float32_t floatX_t;
        };
     
        template <>
        struct MetaTypedef<1>
        {
            typedef int8_t intX_t;
            typedef uint8_t uintX_t;
        };
     
        // and so on ...
    Ensuite je fait dans un template par exemple :
    github - /src/cmath_vec3.subs.h
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
        template <typename TYPE>
        struct vec_xnyz
        {
            TYPE x;
            typename MetaTypedef <sizeof(TYPE)>::uintX_t : sizeof(TYPE) * 8; // on saute sizeof(TYPE) octets
            TYPE y;
            TYPE z;
     
            // fonctions
        };
    Ce qui me permet l'ecriture de vec4_t
    github - /src/cmath_vec4.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
    19
    20
    21
    22
    23
     
        template <typename TYPE>
        struct vec4_t
        {
            union
            {
                struct
                {
                    TYPE x;
                    TYPE y;
                    TYPE z;
                    TYPE w;
                };
     
                // [ ... ]
     
                vec_xnyz <TYPE> xzw;
     
                // [ ... ]
            };
     
            // fonctions
        };
    Cela fonctionne a merveille lorsque je fait ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    vec4_t <int32_t> a;
    vec4_t <double> b;
     
    a.zxy = vec3_t<int32_t> (b.xzw);
    Mais si sizeof(TYPE) > 8 octets comme par exemple pour une matrice 4x4 :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    vec4_t <vec4_t <double> > matrix;
     
    // ...
    J'obtiens a la compilation sous clang :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    warning: size of anonymous bit-field (256 bits) exceeds size of its type; value will be truncated to 32 bits
    Ce qui est normal car je n'ai pas de specialisation de MetaTypedef pour ADDRESS_SIZE = sizeof(vec_xnyz <double>) = 32 car uint256_t n'existant pas. De plus ce message est tres bizar car dans mon cas, la valeur dans le bit field anonyme n'a aucune importance, donc qu'elle soit tronquee sur 32 bits a aussi aucune importance. Hors j'ai pour habitude de compiler en mode release avec un -Werror, donc je doit me debarasser de ce warning absolument.

    Quelqu'un aurait il une solution ?

    Merci bien !

    PS:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    > clang++ --version
    Apple LLVM version 5.0 (clang-500.2.79) (based on LLVM 3.3svn)
    Target: x86_64-apple-darwin13.0.0
    Thread model: posix

  2. #2
    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,

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    template <>
        struct MetaTypedef<256/8>
        {
            typedef int8_t intX_t[256/8];
            typedef uint8_t uintX_t[256/8];
        };
    ? (Vraiment pas sur)

  3. #3
    Membre actif
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2009
    Messages
    219
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France

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

    Informations forums :
    Inscription : Juin 2009
    Messages : 219
    Points : 239
    Points
    239
    Par défaut
    Salut Iradrille!

    Non ca ne fonctionne pas car les bitfield ne peuvent pas etre sur autre chose que des (unsigned) integers. Clang le confirme bien :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    error: anonymous bit-field has non-integral type 'typename MetaTypedef<sizeof(vec4_t<double>)>::uintX_t' (aka 'uint8_t [32]')
    Mais merci beaucoup, je n'y avait pas penser !

  4. #4
    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,

    Pourquoi multiplies-tu sizeof(TYPE) par 8 la valeur renvoyée par sizof est, déjà une valeur correspondant au nombre de byte. Si tu multiplie encore cette valeur par 8, tu te trouves à une adresse qui correspond à 8 fois la taille du type envisagé. Je ne suis pas sur du tout que ce soit ce que tu souhaites faire
    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

  5. #5
    Membre actif
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2009
    Messages
    219
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France

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

    Informations forums :
    Inscription : Juin 2009
    Messages : 219
    Points : 239
    Points
    239
    Par défaut
    Salut koala01,

    Et bien, les bit-field sont en bits et non en octets d'ou la multiplication par 8 pour creer un padding de sizeof(TYPE) octets et non sizeof(TYPE) bits.

  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 LastSpear Voir le message
    Salut koala01,

    Et bien, les bit-field sont en bits et non en octets d'ou la multiplication par 8 pour creer un padding de sizeof(TYPE) octets et non sizeof(TYPE) bits.
    Oui, en effet, au temps pour moi... Je n'avais pas percuté sur le fait que c'était un bitfield un résidu des vapeurs de la saint sylvestre sans doute
    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 régulier
    Homme Profil pro
    Étudiant
    Inscrit en
    Septembre 2007
    Messages
    60
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Septembre 2007
    Messages : 60
    Points : 71
    Points
    71
    Par défaut
    Bonjour,

    Etant donné que tu n'utilises que des bitfields multiples de 8, pourquoi ne les remplaces-tu pas par un tableau de bytes de la bonne taille ?

    Par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    template <typename TYPE>
        struct vec_xnyz
        {
            TYPE x;
            uint8_t __dummy[ sizeof(TYPE) ];
            TYPE y;
            TYPE z;
     
            // fonctions
        };
    A vue de nez, ça devrait marcher.
    T'auras quelques problèmes du fait qu'il y a un membre en plus, mais ça devrait être tout.

  8. #8
    Membre actif
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2009
    Messages
    219
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France

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

    Informations forums :
    Inscription : Juin 2009
    Messages : 219
    Points : 239
    Points
    239
    Par défaut
    Salut k1000,

    Merci ! J'esperais eviter de creer un padding a l'aide d'un membre non utiliser en faite, car pourrait etre utiliser. Et cette solution nous force a nommer chaque padding distinctement dans une meme structure. C'est pour ces raison que j'utilise les bitfields anonymes. Par ailleur, je crois que les specifications de C++ reservent tout les symboles commenceant ou contenant un '__' pour ceux du compilateur. Et pas moyen d'instancier un membre sans nom. Le mettre en private peut etre, ou alors un __attribute__((deprecated)) eventuellement ... Mais reste le probleme de nommer un membre sans l'utiliser, qui est un peut paradoxal (surtout le __attribute__((unused)) !).

    L'ideal aurait ete un equivalent du FieldOffset de C#, ou alors que GCC et clang ne generent pas de warning car etant legal d'un point de vu des specifications de C++. En plus, pas moyen d'ignorer ce warning avec un #pragma GCC diagnostic ignored ...

    Les seuls work around que j'ai pour le moment sont :
    - le flag -isystem pour definir le dossier des headers de la librairie;
    - le flag -w pour ignorer tout les warnings.
    Mais les deux ne peuvent etre persistante car etant celon moi une regression dans la maintenabilitee du code.

  9. #9
    Membre actif
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2009
    Messages
    219
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France

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

    Informations forums :
    Inscription : Juin 2009
    Messages : 219
    Points : 239
    Points
    239
    Par défaut
    Victoire !

    Je viens d'avoir trouver une solution permetant d'avoir des objets de taille <= 32 octets. (C'est deja ca de gagner )

    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
     
    #define cmath_padding(bytes) \                      
         struct \       
         { \            
             typename MetaTypedef <bytes>::uintX_t : bytes; \
             typename MetaTypedef <bytes>::uintX_t : bytes; \
             typename MetaTypedef <bytes>::uintX_t : bytes; \
             typename MetaTypedef <bytes>::uintX_t : bytes; \
             typename MetaTypedef <bytes>::uintX_t : bytes; \
             typename MetaTypedef <bytes>::uintX_t : bytes; \
             typename MetaTypedef <bytes>::uintX_t : bytes; \
             typename MetaTypedef <bytes>::uintX_t : bytes; \
         } __attribute__((packed)) 
     
        template <typename TYPE>
        struct vec_xnyz
        {
            TYPE x;
            cmath_padding(sizeof(TYPE));
            TYPE y;
            TYPE z;
     
            // fonctions
        };
    Je passe le sujet en resolut.

  10. #10
    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
    En jouant avec l'alignement 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
    struct vec4 { int x, y, z, w; };
     
    struct xnyz {
    	int x;
    	__declspec(align(8)) int y;
    	int z;
    };
    vec4 a = {1, 2, 3, 4};
    xnyz xzw = *reinterpret_cast<xnyz*>(&a);
     
    assert(xzw.x == 1);
    assert(xzw.y == 3);
    assert(xzw.z == 4);
    (syntaxe MSVC, je connais pas celle de GCC)

    edit : ha, bah tu as trouvé une solution entre temps.

  11. #11
    Membre régulier
    Homme Profil pro
    Étudiant
    Inscrit en
    Septembre 2007
    Messages
    60
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Septembre 2007
    Messages : 60
    Points : 71
    Points
    71
    Par défaut
    Tu vas avoir besoin de nommer le champs quand-même : le standard interdit les structures anonymes.

    Cette solution avec les champs directement dans vec_xnyz ira bien, sauf si l'attribut packed est nécessaire.

    Pour être franc, la solution de devoir se limiter à 32bytes me satisfait pas. Mais ça, c'est mon perfectionnisme

  12. #12
    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 k1000 Voir le message
    Cette solution avec les champs directement dans vec_xnyz ira bien, sauf si l'attribut packed est nécessaire.
    Il est nécessaire : l'alignement sera de sizeof(TYPE).
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    struct Foo {
       char a; // 0
       int b; // 1
       char c; // 8
       double d; // 12
       char e; // 20
       char f; // 28
    };
    (Et il y à peut être un alignement minimum de 4 (32 bits) ou 8 (64 bits))

    En calant 8 champs anonymes ça crée un padding de 8 * sizeof(TYPE) du coup.

    edit : mais du coup ...
    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
    struct vec4 { int x, y, z, w; };
     
    struct xnyz {
    	int x;
    	char : 1;
    	int y;
    	int z;
    };
     
    vec4 a = {1, 2, 3, 4};
    xnyz xzw = *reinterpret_cast<xnyz*>(&a);
     
    assert(xzw.x == 1);
    assert(xzw.y == 3);
    assert(xzw.z == 4);

  13. #13
    Membre actif
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2009
    Messages
    219
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France

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

    Informations forums :
    Inscription : Juin 2009
    Messages : 219
    Points : 239
    Points
    239
    Par défaut
    Citation Envoyé par Iradrille Voir le message
    En jouant avec l'alignement 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
    struct vec4 { int x, y, z, w; };
     
    struct xnyz {
    	int x;
    	__declspec(align(8)) int y;
    	int z;
    };
    vec4 a = {1, 2, 3, 4};
    xnyz xzw = *reinterpret_cast<xnyz*>(&a);
     
    assert(xzw.x == 1);
    assert(xzw.y == 3);
    assert(xzw.z == 4);
    (syntaxe MSVC, je connais pas celle de GCC)

    edit : ha, bah tu as trouvé une solution entre temps.
    C'est vrai que sa marche dans le cas que tu proposes, mais pas de maniere general malheureusement (sa aurait ete trop beau sinon ) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #include <cstdio>
     
    struct xynz {
        int x;
        int y;
        int z __attribute__ ((aligned (12)));
    };
     
    int main()
    {
        printf("%lu\n", sizeof(xynz));
     
        return 0;
    }
    clang++ -o test test.cpp
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    main.cpp:7:27: error: requested alignment is not a power of 2
        int z __attribute__ ((aligned (12)));
                              ^        ~~
    Autres cas limite :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    #include <cstdio>
     
    struct xny {
        int x;
        int y __attribute__ ((aligned (8)));
    };
     
    int main()
    {
        printf("%lu\n", sizeof(xny)); // affiche 16 != 3 * sizeof(int)
     
        return 0;
    }
    C'est la que je suis d'avis que le C++ devrai prendre exemple sur le GLSL pour avoir quelque chose du genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    struct xynz {
        int x;
        int y;
        int z __attribute__ ((offset (12)));
    };
    Citation Envoyé par k1000 Voir le message
    Tu vas avoir besoin de nommer le champs quand-même : le standard interdit les structures anonymes.

    Cette solution avec les champs directement dans vec_xnyz ira bien, sauf si l'attribut packed est nécessaire.

    Pour être franc, la solution de devoir se limiter à 32bytes me satisfait pas. Mais ça, c'est mon perfectionnisme
    C'est certain que c'est pas le plus eleguant ... Pourquoi ce limiter a 32bytes ?

    Par chance, je n'ai pas de raisons d'avoir besoin de plus de 32bytes pour des matrices. Et cette solution me permet d'eviter d'instancier des membres ne devant pas etre utiliser, lui heurtant mon perfectionnisme.

    Citation Envoyé par Iradrille Voir le message
    Il est nécessaire : l'alignement sera de sizeof(TYPE).
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    struct Foo {
       char a; // 0
       int b; // 1
       char c; // 8
       double d; // 12
       char e; // 20
       char f; // 28
    };
    (Et il y à peut être un alignement minimum de 4 (32 bits) ou 8 (64 bits))

    En calant 8 champs anonymes ça crée un padding de 8 * sizeof(TYPE) du coup.

    edit : mais du coup ...
    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
    struct vec4 { int x, y, z, w; };
     
    struct xnyz {
    	int x;
    	char : 1;
    	int y;
    	int z;
    };
     
    vec4 a = {1, 2, 3, 4};
    xnyz xzw = *reinterpret_cast<xnyz*>(&a);
     
    assert(xzw.x == 1);
    assert(xzw.y == 3);
    assert(xzw.z == 4);
    Trop genial ! C'est parfait ! J'avais oublier d'utiliser les padding implicite : ca sa fonctionne trop bien ton truc ! J'adopte !

    Un grand merci a tous !

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

Discussions similaires

  1. Etat est plus large que le papier
    Par lebienestrare dans le forum VB 6 et antérieur
    Réponses: 5
    Dernier message: 04/09/2006, 20h55
  2. [DBCOMBOBOX] liste est plus large que le combo lui-même
    Par valoji dans le forum Bases de données
    Réponses: 3
    Dernier message: 18/05/2006, 16h59
  3. un tableau plus large que la fenêtre.
    Par maniaco_jazz dans le forum Balisage (X)HTML et validation W3C
    Réponses: 3
    Dernier message: 04/12/2005, 23h25
  4. [Datareport] Etat plus large que le papier
    Par SpaceFrog dans le forum VB 6 et antérieur
    Réponses: 5
    Dernier message: 09/09/2002, 11h45

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