Thread: Finding the "address" of a bitfield

  1. #1
    Registered User
    Join Date
    Nov 2008
    Posts
    127

    Finding the "address" of a bitfield

    So I obviously can't take the address of a bitfield, but is there a way to get the address of the field holding the bitfield? What I'm trying to do is find the address of the parent field of a bitfield in a class. For example

    Code:
    class Foo
    {
    public:
      int a;
      int b : 4;
      int c : 28;
    };
    
    void func()
    {
      Foo foo;
    
      printf("%u\n", offsetof(Foo, c));
    }
    My goal is to get the offset address of the int storing c in class Foo. But offsetof uses the address of c, so I get a compile error since c is a bitfield. What I wanted as output from the above would be "4", since an int is 4 bytes (on my system). So the int holding both b & c starts 4 bytes from the start of the Foo class.

    Is there any way to do this in c/c++?

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Out of curiosity, but why do you want to do this?
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    Registered User
    Join Date
    Apr 2013
    Posts
    1,658
    Quote Originally Posted by homer_3 View Post
    Is there any way to do this in c/c++?
    Try using a union of unsigned integer(s) and bit fields.

  4. #4
    Registered User
    Join Date
    Nov 2008
    Posts
    127
    Quote Originally Posted by laserlight View Post
    Out of curiosity, but why do you want to do this?
    It'd due to general limitations. I need a way to output some numeric identifier for the class field. The offset from the start of the class seems like the best identifier to me.

    Quote Originally Posted by rcgldr
    Try using a union of unsigned integer(s) and bit fields.
    Would be nice, but I can't change the code.

  5. #5
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    > Would be nice, but I can't change the code.
    Any other pertinent information you'd like to share with us, before we try and think up some other ideas for you to reject.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  6. #6
    Registered User
    Join Date
    Nov 2008
    Posts
    127
    Quote Originally Posted by Salem View Post
    > Would be nice, but I can't change the code.
    Any other pertinent information you'd like to share with us, before we try and think up some other ideas for you to reject.
    Wow, you're upset. I did give a very specific example. Why would there be an expectation that the example could be changed in order to solve the problem?

  7. #7
    Registered User
    Join Date
    Mar 2010
    Posts
    583
    Seems quite an odd thing to want. So odd that I'm not convinced you really want it

    It's an interesting question though, and I think I thought of a horrible way to do it. If you can't make a proper union, you can fake it, provided your containers are all the same size and it is really the container offset that you want.

    • Create an object of type foo
    • Point an int* at it
    • Adjust a field, using the foo pointer
    • Examine the elements of the int* array (you can use sizeof(foo) to get an upper limit on the number of elements) and see which one has changed (initialise it all to a known value like 0 to start with)


    You can use sizeof(foo) to work out the number of elements in the array. You can wrap it all up in a horrible macro so you have your own sort of offsetof-alike cheat.

    If you have different sized containers.... that could be fun. You could use a char* array to get the byte offset then relate that back to the original type somehow. If you have typeof() on your compiler (e.g. GCC) you could use that to get the type.

  8. #8
    Registered User
    Join Date
    Mar 2010
    Posts
    583
    I did it like this:
    Code:
    unsigned get_offset(void * f)
    {
       int * arr = (int*)f;
       int i = 0;
       while (!arr[i])
          i++;  
       return i * sizeof(int);  
    }
    
    #define GetOffset(str, field) ({str f; memset(&f, 0, sizeof(f)); f.field = 1; get_offset(&f);})
    Called like:
    Code:
      printf("\nb: %u\n", GetOffset(Foo, b) );
    I think that's the first time I've ever used a void* and meant it
    I shouldn't have called it GetOffset since that's not what it does.... GetIntSizedBitfieldContainerOffset would be better but depends how much you like typing.
    I could have put the whole thing in a macro, but writing many lines of straight code inside a macro always feels wrong to me.
    Last edited by smokeyangel; 08-14-2013 at 03:36 PM.

  9. #9
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    > Wow, you're upset. I did give a very specific example. Why would there be an expectation that the example could be changed in order to solve the problem?
    1. You already knew that you can't take the address of a bit-field.
    2. You asked "Is there any way to do this in c/c++?"

    Now when people say "any way", that usually means that nothing is off the table as far as solutions go.

    I'm not upset, but you should apologise to rcgldr for wasting their time on what would otherwise be a fine suggestion.

    Oh, and just to keep things interesting, there's a bug in smokeyangel's solution (very subtle one, it'll be interesting to see who can spot it).
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  10. #10
    Registered User
    Join Date
    Mar 2010
    Posts
    583
    Bug? I have no idea!

    I can think of a number of things that are bad about it:
    • The types are a disaster waiting to happen (using signed int, and using 32-bit types at all). I should have used size_t, and cout for the printing, since C++ doesn't have a format specifier for size_t.
    • The macro is horribly illegal. GCC says "ISO C++ forbids braced-groups within expressions" with -pedantic. I'm not thrilled about this use of a macro, even if there's a legal way. It seems a lot of code to spatter all around the place. I don't know any other way to generate "foo->a" from the name 'a', but wonder if there's a way to not have so much live inside the macro.
    • The code assumes it can safely access int pointers at the address of foo, which might not be true (e.g. Foo is packed/unaigned). Should use a char* and figure out the int container from that


    But they're not a specific "bug", so I guess you're thinking of something else. Curious!

  11. #11
    Registered User
    Join Date
    Apr 2006
    Posts
    2,149
    I think you want f.field = ~0 (aka -1) so that it finds where foo begins, not ends.
    It is too clear and so it is hard to see.
    A dunce once searched for fire with a lighted lantern.
    Had he known what fire was,
    He could have cooked his rice much sooner.

  12. #12
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    Quote Originally Posted by homer_3 View Post
    What I wanted as output from the above would be "4", since an int is 4 bytes (on my system). So the int holding both b & c starts 4 bytes from the start of the Foo class.
    That is not necessarily true, even if an int is 4 bytes on your system.

    If you want to be able to refer to specific bits, better to use bitwise operations rather than bitfields. The layout of bitfields is implementation defined, and there are more possibilities in your code than bundling b and c into a single 4-byte word, even if int is 4 bytes on your system. There is, for example, nothing preventing the compiler from packing fields b and c into separate words. The fact they can potentially fit does not mean the compiler is required to fit them in.

    With bitwise operations you can explicitly control the packing of bits.
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Buttercup, and read this, this, and this before posting again.

  13. #13
    Registered User
    Join Date
    Mar 2010
    Posts
    583
    Quote Originally Posted by King Mir View Post
    I think you want f.field = ~0 (aka -1) so that it finds where foo begins, not ends.
    Aha, nice spot. I hadn't realised just how "implementation defined" they were! I had a set of rules in my head from a specific platform (where a bitfield can't staddle two units).

    Quote Originally Posted by C++11 draft standard
    Bit-fields are packed into some
    addressable allocation unit. [ Note: Bit-fields straddle allocation units on some machines and not on others.
    Bit-fields are assigned right-to-left on some machines, left-to-right on others. — end note ]
    Yeesh. "Do whatever you want"....

    This thread has made me ask "why on earth would anyone ever use these things?". Googling seems to show that people do use bitfields in the hope of getting precise bit layours, and amazingingly live to tell the tale. I suppose such programs are already extremely platform and compiler dependent, so portability is a non issue. In that case relying on implementation defined behaviour is ok.

    OP: You wrote:
    I need a way to output some numeric identifier for the class field. The offset from the start of the class seems like the best identifier to me.
    These not-unique "numeric identifiers" have me puzzled. Could you explain what they're used for?

  14. #14
    Registered User
    Join Date
    Nov 2008
    Posts
    127
    Quote Originally Posted by grumpy View Post
    There is, for example, nothing preventing the compiler from packing fields b and c into separate words. The fact they can potentially fit does not mean the compiler is required to fit them in.
    Why do they have to make my life so hard! Thanks though, good info to know.

    It looks like smokey has the best solution. I think I can work with that, thanks!

  15. #15
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    > f.field = 1
    The specific bug I was thinking of is the case where the field in question is say 'signed int a:1'.
    Being signed, and with only 1 bit, the only valid values that can be stored are 0 and -1, so technically assigning 1 is a numeric overflow.

    King Mir's approach nicely solves a couple of issues.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 19
    Last Post: 01-06-2012, 03:01 PM
  2. "*x + *x++" Address/Pointer "?"
    By Marth_01 in forum C Programming
    Replies: 10
    Last Post: 11-05-2008, 04:33 AM
  3. bitfield "array"
    By bibsik in forum C++ Programming
    Replies: 6
    Last Post: 04-13-2006, 12:34 AM
  4. "itoa"-"_itoa" , "inp"-"_inp", Why some functions have "
    By L.O.K. in forum Windows Programming
    Replies: 5
    Last Post: 12-08-2002, 08:25 AM
  5. "CWnd"-"HWnd","CBitmap"-"HBitmap"...., What is mean by "
    By L.O.K. in forum Windows Programming
    Replies: 2
    Last Post: 12-04-2002, 07:59 AM