2009-02-11 4 views
3

La version courte est la suivante: Comment apprendre la taille (en bits) d'un champ individuel d'un champ C++?Obtention de la taille d'un champ individuel à partir d'un champ de structure C++

Pour clarifier les choses, un exemple du champ je parle:

struct Test { 
    unsigned field1 : 4; // takes up 4 bits 
    unsigned field2 : 8; // 8 bits 
    unsigned field3 : 1; // 1 bit 
    unsigned field4 : 3; // 3 bits 
    unsigned field5 : 16; // 16 more to make it a 32 bit struct 

    int normal_member; // normal struct variable member, 4 bytes on my system 
}; 

Test t; 
t.field1 = 1; 
t.field2 = 5; 
// etc. 

Pour obtenir la taille de l'ensemble de l'objet de test est facile, nous disons simplement

sizeof(Test); // returns 8, for 8 bytes total size 

Nous pouvons obtenir un membre struct normal par

sizeof(((Test*)0)->normal_member); // returns 4 (on my system) 

Je voudrais savoir comment obtenir la taille d'un champ individuel, disons Test :: field4. L'exemple ci-dessus pour un membre struct struct ne fonctionne pas. Des idées? Ou quelqu'un sait-il une raison pour laquelle cela ne peut pas fonctionner? Je suis assez convaincu que sizeof ne sera pas utile car il ne fait que retourner la taille en octets, mais si quelqu'un sait le contraire, je suis tout ouïe.

Merci!

+0

Je pense que vous pourriez être encerclé, mais j'aimerais me tromper. –

+0

Je voudrais saisir cette opportunité pour continuer ma croisade contre les champs de bits - ne les utilisez pas: http://stackoverflow.com/questions/289900/why-this-unions-size-is-2-with- bitfields/290855 # 290855 –

Répondre

10

Vous pouvez calculer la taille au moment de l'exécution, FWIW, par exemple:

//instantiate 
Test t; 
//fill all bits in the field 
t.field1 = ~0; 
//extract to unsigned integer 
unsigned int i = t.field1; 
... TODO use contents of i to calculate the bit-width of the field ... 
+0

Cela n'a pas de sens, pourquoi n'utiliserait-on pas d'autres suggestions de temps de compilation déjà mentionnées? –

+0

Puisque vous devez de toute façon connaître les champs, cela ne sert à rien au moment de l'exécution ... –

+0

Les autres suggestions nécessitent de changer le code source du champ de bits, ce n'est pas le cas. –

1

Ceci est impossible

Réponse à un commentaire: Parce que le type est juste un int, il n'y a pas de type 'bit'. La syntaxe d'affectation de champ de bits est juste courte pour effectuer le code bit à bit pour les lectures et les écritures.

+0

Avez-vous de la documentation pour me diriger vers? Ou au moins ton raisonnement? Je suis juste curieux à ce stade. –

1

Je ne pense pas que tu puisses le faire. Si vous vraiment besoin de la taille, je vous suggère d'utiliser un #define (ou, mieux encore, si possible une variable const - Je ne suis pas sûr que ce soit légal) comme si:

#define TEST_FIELD1_SIZE 4 
struct Test { 
    unsigned field1 : TEST_FIELD1_SIZE; 
    ... 
} 
+0

const est légal, à condition qu'il s'agisse d'un type intégral (il ne peut en aucun cas être réservé un demi-bit). C'est le meilleur que je puisse faire aussi. Merci. –

5

Vous ne pouvez pas prendre le sizeof un bitfield et obtenir le nombre de bits.

Votre meilleur pari serait utiliser #define s ou enum s:

struct Test { 
    enum Sizes { 
     sizeof_field1 = 4, 
     sizeof_field2 = 8, 
     sizeof_field3 = 1, 
     sizeof_field4 = 3, 
     sizeof_field5 = 16, 
    }; 

    unsigned field1 : sizeof_field1; // takes up 4 bits 
    unsigned field2 : sizeof_field2; // 8 bits 
    unsigned field3 : sizeof_field3; // 1 bit 
    unsigned field4 : sizeof_field4; // 3 bits 
    unsigned field5 : sizeof_field5; // 16 more to make it a 32 bit struct 

    int normal_member; // normal struct variable member, 4 bytes on my system 
}; 

printf("%d\n", Test::sizeof_field1); // prints 4 

Par souci de cohérence, je crois que vous pouvez déplacer normal_member jusqu'au sommet et ajouter une entrée à l'aide Sizessizeof(normal_member). Cela dérange avec l'ordre de vos données, cependant.

2

En utilisant ChrisW's idea (Nice, en passant), vous pouvez créer une macro d'aide:

#define SIZEOF_BITFIELD(class,member,out) { \ 
    class tmp_;        \ 
    tmp_.member = ~0;      \ 
    unsigned int tmp2_ = tmp_.member;  \ 
    ++tmp2_;        \ 
    out = log2(tmp2_);      \ 
} 

unsigned int log2(unsigned int x) { 
    // Overflow occured. 
    if(!x) { 
     return sizeof(unsigned int) * CHAR_BIT; 
    } 

    // Some bit twiddling... Exploiting the fact that floats use base 2 and store the exponent. Assumes 32-bit IEEE. 
    float f = (float)x; 
    return (*(unsigned int *)&f >> 23) - 0x7f; 
} 

Utilisation:

size_t size; 
SIZEOF_BITFIELD(Test, field1, size); // Class of the field, field itself, output variable. 

printf("%d\n", size); // Prints 4. 

Mes tentatives d'utiliser les fonctions templated ont échoué. Je ne suis pas un expert sur les modèles, cependant, il peut encore être toujours possible d'avoir une méthode propre (par exemple sizeof_bitfield(Test::field1)).

+0

A propos d'avoir une "méthode propre", et étant donné l'existence de: http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/refmanual/has-xxx-template-def.html est possible de générer (à travers une macro) un template donné le nom du champ. L'avantage pourrait être que le calcul devrait avoir lieu au moment de la compilation: on pourrait donc écrire une définition récursive "normale" de log2 (après la fameuse fonction factorielle de compilation) et l'optimiser. – Blaisorblade

Questions connexes