C bitfields guarantees

Steven Schveighoffer schveiguy at gmail.com
Sat Jul 6 03:23:20 UTC 2024


On Saturday, 6 July 2024 at 00:16:23 UTC, Walter Bright wrote:
> On 7/5/2024 2:12 PM, Steven Schveighoffer wrote:
>> I also tested the following, and found it too shows 
>> discrepancies.
>> 
>> ```c
>> struct S {
>>      unsigned short x;
>>      unsigned int a : 12;
>>      unsigned int b : 12;
>>      unsigned int c : 8;
>> };
>> ```
>
> The following will also show discrepancies:
>
> ```
> struct T {
>     unsigned short x;
>     unsigned int y;
> }
> ```
>
> for the same reason.

I tested this struct, and there were no discrepancies between 
compilers. All compilers put 2 bytes of padding between the 
`ushort` and the `uint`.

> It's actually based on the *alignment* of the preceding field. 
> I'm regret not saying that, but that's what I meant with the 
> fields need to be of the same type, so they have the same 
> alignment. If the uint bitfield started off aligned at a uint 
> boundary, my statement holds.

Hm..., well it's not ideal to require the user to nudge the 
compiler for the desired layout. It's an odd thing to say that a 
uint bitfield may not be uint aligned, even if the equivalent 
uint value would be.

The documentation note we talked about was simple -- just always 
use the same type for your bitfields and it works. This is 
different. Not impossible to learn, but for sure more challenging.

>
> When mixing field types of different sizes, there will be 
> different alignments of those fields on different 
> platforms/compilers, whether or not bitfields are involved.
>

The confusing thing here is that the alignment does *not* obey 
the alignment of the containing type. And how it is aligned 
depends instead on the *previous* member (sometimes). This is not 
the case for full-sized uints.

I will note that I'm reading that ulong is aligned to 4-bytes on 
32-bit linux, and so this does make an alignment difference even 
for non-bitfields.

My recommendation still is either:

1. Denote D bitfields by a specified layout system (pick the most 
common C one and do that). C bitfields can match the C compiler.
2. Simply forbid problematic alignments at compile time:

```d
struct S {
    uint x;
    uint64 a : 24;
    uint64 b : 24;
    uint64 c : 16;
}

// error, alignment of bitfield `a` may not match C layout, 
please use padding or aligned bitfields to specify intended 
layout.

// these are OK.
struct SWithPadding {
    uint x;
    uint _; // padding
    uint64 a : 24;
    uint64 b : 24;
    uint64 c : 16;
}

struct SPacked {
    uint64 x : 32;
    uint64 a : 24;
    uint64 b : 24;
    uint64 c : 16;
}
```

Maybe the error only occurs if you specify a compiler switch?

-Steve


More information about the Digitalmars-d mailing list