May 04
On 5/4/2024 10:05 AM, Timon Gehr wrote:
> This is explicitly called a `union`, so I really do not see what you are trying to say.

An anonymous union is simply a way to specify layout. No actual union is created, as there is no point to it. How would one refer to an anonymous union? The same goes for anonymous structs.


> Clearly bitfields are a new and distinct way fields can share the same `.offsetof` in D. Before bitfields, such fields would overlap given they both were of a type with a positive size. With bitfields there is no such overlap.

Bitfields do overlap, which is why they are accessed with shift and mask.

Besides, the context here is with existing introspection. Existing introspection will treat them as overlapping fields.


> BTW: what about `sizeof`? I think in C++ this is disallowed on a bitfield.

```
struct S { int b:3; }
pragma(msg, S.b.sizeof);
```
prints 4LU, as it applies to the type. To get the field width, use .max, as already discussed.
May 05
On 5/4/24 22:17, Walter Bright wrote:
> On 5/4/2024 10:05 AM, Timon Gehr wrote:
>> This is explicitly called a `union`, so I really do not see what you are trying to say.
> 
> An anonymous union is simply a way to specify layout. No actual union is created, as there is no point to it. How would one refer to an anonymous union? The same goes for anonymous structs.
> ...

Well, now you are simply slicing the terminology in a weird way. `union` and `struct` are tools to lay out data, anonymous or otherwise, whether you generate typeinfo or otherwise.

> 
>> Clearly bitfields are a new and distinct way fields can share the same `.offsetof` in D. Before bitfields, such fields would overlap given they both were of a type with a positive size. With bitfields there is no such overlap.
> 
> Bitfields do overlap, which is why they are accessed with shift and mask.
> ...

They do not overlap if not put in a union (anonymous or otherwise). Otherwise, changing the value of one bitfield would affect the value of another one. The fact that they occupy space in the same byte and that the processor can only address memory at byte granularity does not imply that the bitfields themselves overlap.

> Besides, the context here is with existing introspection. Existing introspection will treat them as overlapping fields.
> 
> 
>> BTW: what about `sizeof`? I think in C++ this is disallowed on a bitfield.
> 
> ```
> struct S { int b:3; }
> pragma(msg, S.b.sizeof);
> ```
> prints 4LU, as it applies to the type. To get the field width, use .max, as already discussed.

Well, then code that is set up to work with data using `.tupleof`, `.offsetof` and `.sizeof` will silently break. Whether you acknowledge that or not, it's simply the truth.

You are breaking the previous invariant that data in a struct lives at relative addresses `data.offsetof..data.offsetof+data.sizeof`.
May 04
On 5/4/2024 4:01 PM, Timon Gehr wrote:
> You are breaking the previous invariant that data in a struct lives at relative addresses `data.offsetof..data.offsetof+data.sizeof`.

The data.sizeof for a bitfield will always be the size of the memory object containing the field. The invariant is not broken.
May 05
On 5/5/24 04:11, Walter Bright wrote:
> On 5/4/2024 4:01 PM, Timon Gehr wrote:
>> You are breaking the previous invariant that data in a struct lives at relative addresses `data.offsetof..data.offsetof+data.sizeof`.
> 
> The data.sizeof for a bitfield will always be the size of the memory object containing the field. The invariant is not broken.

I do not understand. I thought bitfields are supposed to match the layout of the associated C compiler. Instead, you seem to now be arguing that there should actually be stringent layout guarantees.

GCC 11.4.0, clang 14.0.0:

```c
#include <stdio.h>
struct __attribute__((packed)) S{
    long long x:8;
};
int main(){
    printf("%ld\n",sizeof(long long)); // 8
    printf("%ld\n",sizeof(struct S)); // 1
}
```

It indeed seems `dmd 2.108.1` disagrees and gives `8` and `8`, but I guess this is a mistake.

In any case, laying the struct out like this is in compliance with C standards even without the additional attribute:

> An implementation may allocate any addressable storage unit large enough to hold a bit-
> field. If enough space remains, a bit-field that immediately follows another bit-field in a
> structure shall be packed into adjacent bits of the same unit. If insufficient space remains,
> whether a bit-field that does not fit is put into the next unit or overlaps adjacent units is
> implementation-defined. The order of allocation of bit-fields within a unit (high-order to
> low-order or low-order to high-order) is i

http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf

Maybe at least redefine `.sizeof` to give the size of the underlying storage unit for a bitfield. Otherwise, you exacerbate the risk of memory corruption due to invalid assumptions about layout.
May 06
On 5/5/2024 2:08 AM, Timon Gehr wrote:
> GCC 11.4.0, clang 14.0.0:
> 
> ```c
> #include <stdio.h>
> struct __attribute__((packed)) S{
>      long long x:8;
> };
> int main(){
>      printf("%ld\n",sizeof(long long)); // 8
>      printf("%ld\n",sizeof(struct S)); // 1
> }
> ```

The sizeof there, in both cases, is giving the size in bytes of the memory object the field is a subset of.


> Maybe at least redefine `.sizeof` to give the size of the underlying storage unit for a bitfield.

That's what it's doing in the example.

BTW, I didn't implement packed bitfields in ImportC. It never occurred to me :-/ I suppose it should get a bugzilla issue.

https://issues.dlang.org/show_bug.cgi?id=24538
May 06

On Tuesday, 23 April 2024 at 01:01:11 UTC, Walter Bright wrote:

>

https://github.com/WalterBright/documents/blob/dcb8caabff76312eee25bb9aa057774d981a5bf7/bitfields.md

Why not use .bitsizeof instead of .bitwidth? For the sake of conformance with .sizeof?

May 06
On 5/6/2024 6:52 AM, Per Nordlöw wrote:
> Why not use `.bitsizeof` instead of `.bitwidth`? For the sake of conformance with `.sizeof`?

Sizeof is in bytes, so I use a different word for number of bits.
May 06
On 5/6/24 09:14, Walter Bright wrote:
> On 5/5/2024 2:08 AM, Timon Gehr wrote:
>> GCC 11.4.0, clang 14.0.0:
>>
>> ```c
>> #include <stdio.h>
>> struct __attribute__((packed)) S{
>>      long long x:8;
>> };
>> int main(){
>>      printf("%ld\n",sizeof(long long)); // 8
>>      printf("%ld\n",sizeof(struct S)); // 1
>> }
>> ```
> 
> The sizeof there, in both cases, is giving the size in bytes of the memory object the field is a subset of.
> ...

This is C and neither sizeof is on a memory object, they are both on types. sizeof on x gives a compile error. However, with the DIP, given that you implement packed bitfields in DMD, when importing an example like this one, `x.sizeof` would be eight times as big as the size of the `struct` it is a part of.

> 
>> Maybe at least redefine `.sizeof` to give the size of the underlying storage unit for a bitfield.
> 
> That's what it's doing in the example.
> ...

Well, the DIP now says `bitfield.sizeof` is `typeof(bitfield).sizeof`. Unless I misunderstand and `typeof(x)` is not `long long`, this should not be the case in this example, because a `long long` is longer than the memory location it is packed into in this case. (I think this is another broken invariant.)

> BTW, I didn't implement packed bitfields in ImportC. It never occurred to me :-/ I suppose it should get a bugzilla issue.
> 
> https://issues.dlang.org/show_bug.cgi?id=24538

Well, that will help, but the point was the C standard does not give the guarantees you assumed to hold earlier, and in practice it in fact does not hold, as in this example.
May 06
On 5/6/2024 1:37 PM, Timon Gehr wrote:
> On 5/6/24 09:14, Walter Bright wrote:
>> On 5/5/2024 2:08 AM, Timon Gehr wrote:
>>> GCC 11.4.0, clang 14.0.0:
>>>
>>> ```c
>>> #include <stdio.h>
>>> struct __attribute__((packed)) S{
>>>      long long x:8;
>>> };
>>> int main(){
>>>      printf("%ld\n",sizeof(long long)); // 8
>>>      printf("%ld\n",sizeof(struct S)); // 1
>>> }
>>> ```
>>
>> The sizeof there, in both cases, is giving the size in bytes of the memory object the field is a subset of.
>> ...
> 
> This is C and neither sizeof is on a memory object, they are both on types. sizeof on x gives a compile error. However, with the DIP, given that you implement packed bitfields in DMD, when importing an example like this one, `x.sizeof` would be eight times as big as the size of the `struct` it is a part of.

Since the memory object that x is in is 1 byte, the sizeof would be 1 byte (if I implemented the packed logic).


> Well, the DIP now says `bitfield.sizeof` is `typeof(bitfield).sizeof`.

Yes, as I didn't know about the packed thing then.

> Well, that will help, but the point was the C standard does not give the guarantees you assumed to hold earlier, and in practice it in fact does not hold, as in this example.

The C standard says nothing about __attribte__((packed), and C doesn't allow sizeof on bit fields, so we can make .sizeof work as we like. The most practical thing is to make it mean the size of the memory object the bitfield is a subset of. Unless (unimplemented) packed bitfields are used, the sizeof is the size of the type.
May 07
On 5/7/24 05:39, Walter Bright wrote:
> The most practical thing is to make it mean the size of the memory object the bitfield is a subset of.

I agree that given the C-like bitfield design you seem to have set your mind on, and given the behavior of `.offsetof` this is a decent behavior for `.sizeof`.

However, this is not what the DIP currently says, so it should be updated.

> Unless (unimplemented) packed bitfields are used, the sizeof is the size of the type.

The size of the memory object has to be whatever the associated C compiler allocates, and according to the standard, it is in principle allowed to pack by default. There is no guarantee that the memory object is in fact at least as big as the type of the bitfield. I am not familiar with bitfield layout on all platforms that D supports via GDC and LDC, but I would not be surprised if on some of them this is actually an issue in practice.