Requiring a fixed position of one field in a struct without extern

I need a field to be the the very first field of a struct for use with things like GS relative addressing on x86 but have no other layout requirements on the struct.

The obvious solution is to just use an extern struct but that forces C compatible types for all other fields:

pub const Cpu = extern struct {
    // must be the first field `@intFromPtr(&cpu) == @intFromPtr(&cpu.self) == @intFromPtr(cpu.self)`
    self: *Cpu,

    // the rest of this struct has no need to be extern and wants to contain
    // slices, auto layout structs, etc but instead has to contort itself to
    // C compatible types

    // some fields are read/modified by assembly, getting the offsets of
    // those fields is `@offsetOf(Cpu, "field")`
};

My current solution is to use an extern wrapper and embed the inner struct manually:

pub const Cpu = struct {
    // can have anything we want here

    // some fields of `Cpu` are read/modified by assembly
    // getting the offsets of those fields is `@offsetOf(Outer, "_cpu") + @offsetOf(Cpu, "field")`

    pub const Outer = extern struct {
        // must be the first field `@intFromPtr(&outer) == @intFromPtr(&outer.self) == @intFromPtr(outer.self)`
        self: *Outer,

        // can't have `cpu: Cpu` as it is an auto type so we need to just slot it in manually
        _cpu: [@sizeOf(Cpu)]u8 align(@alignOf(Cpu)),

        pub fn cpu(outer: *Outer) *Cpu {
            return @ptrCast(&outer._cpu);
        }
    };
};

Does anyone know of a better way of doing this?

I once stumbled upon similar problem https://github.com/ziglang/zig/issues/168#issuecomment-2154197062. I don’t really have a good solution for you.

I’ve always been handling it the same way as OP. It’s great if the language can offer a better solution, but for now, I can still accept the current situation.

Sometimes the field you want to be first is already put first by Zig auto layout. eg if it has the biggest alignment and is also the first in the list

In that case just adding a comptime assert that @offsetOf is 0 is enough for me. If someday Zig changes, and my projectis still active, I’ll think harder