5

The short version is: How do I learn the size (in bits) of an individual field of a c++ field?

To clarify, an example of the field I am talking about:

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.

To get the size of the entire Test object is easy, we just say

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

We can get a normal struct member through

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

I would like to know how to get the size of an individual field, say Test::field4. The above example for a normal struct member does not work. Any ideas? Or does someone know a reason why it cannot work? I am fairly convinced that sizeof will not be of help since it only returns size in bytes, but if anyone knows otherwise I'm all ears.

Thanks!

Jeffrey Martinez
  • 4,384
  • 2
  • 31
  • 36
  • I think you might be hooped, but I'd like to be proven wrong. – Ryann Graham Feb 11 '09 at 23:02
  • I'd like to take this opportunity to continue my crusade against bitfields - just don't use them: http://stackoverflow.com/questions/289900/why-this-unions-size-is-2-with-bitfields/290855#290855 – Michael Burr Feb 11 '09 at 23:34

6 Answers6

10

You can calculate the size at run time, fwiw, e.g.:

//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 ...
ChrisW
  • 54,973
  • 13
  • 116
  • 224
5

You cannot take the sizeof a bitfield and get the number of bits.

Your best bet would be use #defines or enums:

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

For the sake of consistency, I believe you can move normal_member up to the top and add an entry in Sizes using sizeof(normal_member). This messes with the order of your data, though.

strager
  • 88,763
  • 26
  • 134
  • 176
3

Seems unlikely, since sizeof() is in bytes, and you want bits.

http://en.wikipedia.org/wiki/Sizeof

building on the bit counting answer, you can use.

http://www-graphics.stanford.edu/~seander/bithacks.html

sfossen
  • 4,774
  • 24
  • 18
3

Using ChrisW's idea (nice, by the way), you can create a helper macro:

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

Usage:

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

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

My attempts to use templated functions have failed. I'm not an expert on templates, however, so it may still be possible to have a clean method (e.g. sizeof_bitfield(Test::field1)).

Community
  • 1
  • 1
strager
  • 88,763
  • 26
  • 134
  • 176
  • About having a "clean method", and given the existence of: http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/refmanual/has-xxx-template-def.html it is possible to generate (through a macro) a template given the field name. The advantage might be that the computation would have to occur at compile-time: therefore one could write a "normal" recursive definition of log2 (following the famous compile-time factorial function) and have it optimized away. – Blaisorblade Mar 26 '11 at 23:14
1

This is not possible

Answer to comment: Because the type is just an int, there is no 'bit' type. The bit field assignment syntax is just short hand for performing the bitwise code for reads and writes.

Matt Davison
  • 1,544
  • 10
  • 11
1

I don't think you can do it. If you really need the size, I suggest you use a #define (or, better yet, if possible a const variable -- I'm not sure if that's legal) as so:

#define TEST_FIELD1_SIZE 4
struct Test {
    unsigned field1 : TEST_FIELD1_SIZE;
    ...
}
Adam Rosenfield
  • 390,455
  • 97
  • 512
  • 589
  • const is legal, as long as it's an integral type (can't reserve half of a bit after all). That's the best I'm able to do as well. Thanks. – Jeffrey Martinez Feb 11 '09 at 23:12