Best way to "bind" this bitfield-using C struct?

Hello!

In the flecs library there is a struct exposed in the header like so:

struct ecs_map_t {
    ecs_bucket_t *buckets;
    int32_t bucket_count;
    unsigned count : 26;
    unsigned bucket_shift : 6;
    struct ecs_allocator_t *allocator;
};

My first thought was to write the Zig counterpart like this:

pub const map_t = extern struct {
    buckets: [*]bucket_t,
    bucket_count: i32,
    count: u26,
    bucket_shift: u6,
    allocator: *allocator_t,
};

However:

error: extern structs cannot contain fields of type ‘u26’

One way I could do it is to replace the two variables with a single u32 and then add accessor functions, but it seems kind of cumbersome. Is there a typical Zig way you can recommend?

This should work:

pub const map_t = extern struct {
    buckets: [*]bucket_t,
    bucket_count: i32,
    x: packed struct(u32) {
        count: u26,
        bucket_shift: u6,
    },
    allocator: *allocator_t,
};

Note that the backing integer of the packed struct has to be C ABI compatible to be allowed inside an extern container.

I still wouldn’t recommend @bitCasting from the C type to the Zig one since C bitfield order is implementation defined (unless you’re very sure about your target).

3 Likes

I actually wonder if C bitfields even have a standardized ABI… there is at least different memory layouts allowed for ‘straddling bitfields’, e.g. see the last paragraph here:

…E.g. at least when either count or bucket_shift would need to grow the memory layout may differ between compilers.

Things like this is basically why I disallow certain C features in the public Sokol header API - since this simplifies bindings to higher level languages.

  • no unions
  • no #defines (instead uses a single anonymous enum for constants)
  • no nested anonymous or unnamed structs
  • …and I also wouldn’t use bitfields, although so far I didn’t see a need for them
1 Like

This is one of those things I’d love to have someone compile a test program across a bunch of compilers, versions and options to see how much they truly differ.

1 Like

I poked Sander (the Flecs author) and he said the struct doesn’t really need to be bound so I think I’ll be able to get away with opaqueing it.

But yes when I wrote the bitfield support for c2z I noticed it was hard (or impossible) to get bitfields correctly working across all platforms. Maybe with some kind of comptime switch check, but I got it working for Windows and was satisfied with that.

4 Likes