22

Why cannot take address of bit-field?

How do I make a pointer to bit-field?

Here is the code...

struct bitfield {
    unsigned int a: 1;
    unsigned int b: 1;
    unsigned int c: 1;
    unsigned int d: 1;
};

int main(void)
{
    struct bitfield pipe = {
        .a = 1, .b = 0,
        .c = 0, .d = 0
    };
    printf("%d %d %d %d\n", pipe.a,
            pipe.b, pipe.c, pipe.d);
    printf("%p\n", &pipe.a); /* OPPS HERE */
    // error: cannot take address of bit-field ...
    return 0;
}
Matt
  • 22,721
  • 17
  • 71
  • 112
sleepy_dog
  • 277
  • 1
  • 2
  • 11

5 Answers5

40

Bitfields members are (typically) smaller than the granularity allowed by pointers, which is the granularity of chars (by definition of char, which by the way is mandated to be 8 bit long at least). So, a regular pointer doesn't cut it.

Also, it wouldn't be clear what would be the type of a pointer to a bitfield member, since to store/retrieve such a member the compiler must know exactly where it is located in the bitfield (and no "regular" pointer type can carry such information).

Finally, it's hardly a requested feature (bitfields aren't seen often in first place); bitfields are used to store information compactly or to build a packed representation of flags (e.g. to write to hardware ports), it's rare that you need a pointer to a single field of them - and if it's needed, you can always resort to a regular struct and convert to bitfield at the last moment.

For all these reasons, the standard says that bitfields members aren't addressable, period. It could be possible to overcome these obstacles (e.g. by defining special pointer types that store all the information needed to access a bitfield member), but it would be yet another overcomplicated dark corner of the language that nobody uses.

Matteo Italia
  • 123,740
  • 17
  • 206
  • 299
  • 9
    +1, _"and no "regular" pointer type can carry such information"_ finally someone pointing out something that it's not just _"the Standard says..."_ – effeffe Nov 25 '12 at 01:19
  • 4
    Actually on 64 bits system a pointer can reference a specific bit. As of 2017 pointers use only 48 bits from the 64 and Intel plans to unroll a hardware which uses 56 bits in the near future. So you can use the highest 3 bits to encode the bit offset inside a byte and with some bits manipulation encode everything inside (void*) or typedef a specific pointer type. You can do it with precompiler macros in C style or templates in C++. But there is no reason to support such an odd feature in the standard. One who needs it can implement it – DanielHsH Oct 24 '17 at 18:43
  • 2
    P.s. it is common to abuse free bits inside a pointer in 64 bits architecture. Linux uses some of them to encode pointer+error code in a single (void*) as return value of constructors of structs. Also kernel slab memory allocator uses the most significant 8 bits of a pointer to store additional data. But then again, it is an abuse of a type not a standard – DanielHsH Oct 24 '17 at 18:48
  • @DanielHsH Another case of the unused bits of a pointer being used is in the language Haskell (and other similar functional languages) where the bits are used to track which constructor was used when dealing with [sum types](https://en.wikipedia.org/wiki/Tagged_union). This practice is known as [pointer tagging](https://ghc.haskell.org/trac/ghc/wiki/Commentary/Rts/HaskellExecution/PointerTagging). – Pharap Jun 27 '18 at 17:08
  • effeffe, that sounds suspiciously like the "no true Scotsman" fallacy. Pointers could quite *easily* be implemented to carry bit positions while still following all the current rules, you just need to disassociate the bit position when not using bit fields. And "the standard says" is the *only* rule that matters, since *it* is what defines the language. – paxdiablo Jul 02 '21 at 07:12
  • -1 "but it would be yet another overcomplicated dark corner of the language that nobody uses." - no, it would enable **generic code**, i.e. template code that works regardless of whether your member variable is a bitfield or not. – PBS May 29 '22 at 06:35
  • @PBS bitfields are completely broken from a generic programming standpoint anyhow, they are a struct-specific hack that just doesn't mix with anything else in the C++ type system, mostly retained for backwards compatibility with C; `unsigned int:1` doesn't exist as a "standalone" type, and bit-fields have only a bunch of very specific operations well-defined. Unless hard pressed for space just avoid them (and even in that case, you are generally better served by plain unsigned integers and enum values). – Matteo Italia May 30 '22 at 09:41
10

You cannot actually have the address of a bit field because the smallest addressable unit in C is a byte (remembering that bytes in C are not necessarily 8 bits wide).

The best you could hope for is the address of the containing set of bytes.

The relevant part of the standard (C11 in this case) is section 6.5.3.2 Address and indirection operators (my emphasis):

The operand of the unary & operator shall be either a function designator, the result of a [] or unary * operator, or an lvalue that designates an object that is not a bit-field and is not declared with the register storage-class specifier.

Given that the unit of addressing is a byte, you may find your bit fields stored as (for example):

            Bit 7   6   5   4   3   2   1   0
              +---+---+---+---+---+---+---+---+
Address: 1234 | a | b | c | d | ? | ? | ? | ? |
              +---+---+---+---+---+---+---+---+
         1235 |   |   |   |   |   |   |   |   |
              +---+---+---+---+---+---+---+---+

You can see that the address of all those bit fields is actually the same (1234), so it's not really that useful for distinguishing them..

For manipulating bit fields, you really should just access them directly and let the compiler sort it out.

Even using bit-wise operators isn't guaranteed to work unless you know how the compiler is laying them out in memory.

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
5

Addresses must be an integer number of bytes, but bit-fields don't have to be, so the C standard specifies that the address operator & cannot be used with them. Of course, if you really want to do things with addresses of bitfields, you can just use the address of the enclosing structure, with some bitwise operations.

1''
  • 26,823
  • 32
  • 143
  • 200
0

You can't print the address of the bit field but you can assigned to some local variable of required size type(typecasting from one bit memory to 2 bytes(for integer type size will be compiler dependent) memory),that can be used for printing the address.

unsigned int x=pipe.a; printf("x=%d",&x);

-1

on a similar note, if you just want to address individual bytes, you could do something like this:

union PAIR  {
    struct { uint8_t l, h; } b;
    uint16_t w;
};

PAIR ax;

you can now access pointers to the pieces like &ax.w, &ax.b.l or &ax.b.h note that this still dont allow you to point to individual bits, see previous explanations about this.

EDIT: fixed example

Martin Olika
  • 2,223
  • 1
  • 12
  • 3
  • 1
    This is just undefined behavior regarding to type punning. and the union tricks the compiler to maybe not war you about it. but it is anyway impossible to access the address of a bit, as a byte is the smalles addressable unit by standard! – dhein Jul 07 '15 at 13:53
  • perhaps. however this trick is used in many emulators and their functionality seems to speak otherwise. for example mame, you can see it here: https://github.com/mamedev/mame/blob/master/src/emu/emucore.h#L93 – Martin Olika Jul 07 '15 at 13:58
  • 1
    You know that your link isn't supporting your answer, do you? The undefined behavior just apears when you derefference it that way. not the structure it self. in your link ti is used in ifdefs for endian safety, what is absolutly legit. you advice to use it for deerefferencing. what is illegal and the result is not usefull either. – dhein Jul 07 '15 at 14:15
  • 1
    Just for your information I stumbled about this: ISO/IEC:9899 (C99 TC3) has on page 102 the foornote 106 on section about bitfields and it states: "The unary & (address-of) operator cannot be applied to a bit-field object; thus, there are no pointers to or arrays of bit-field objects." – dhein Jul 27 '15 at 14:57