Extern Structs
Normal structs in Zig do not have a defined layout; extern
structs are
required for when you want the layout of your struct to match the layout of your
C ABI.
Let's create an extern struct. This test should be run with x86_64
with a
gnu
ABI, which can be done with -target x86_64-native-gnu
.
const expect = @import("std").testing.expect;
const Data = extern struct { a: i32, b: u8, c: f32, d: bool, e: bool };
test "hmm" {
const x = Data{
.a = 10005,
.b = 42,
.c = -10.5,
.d = false,
.e = true,
};
const z = @as([*]const u8, @ptrCast(&x));
try expect(@as(*const i32, @ptrCast(@alignCast(z))).* == 10005);
try expect(@as(*const u8, @ptrCast(@alignCast(z + 4))).* == 42);
try expect(@as(*const f32, @ptrCast(@alignCast(z + 8))).* == -10.5);
try expect(@as(*const bool, @ptrCast(@alignCast(z + 12))).* == false);
try expect(@as(*const bool, @ptrCast(@alignCast(z + 13))).* == true);
}
This is what the memory inside our x
value looks like.
Field | a | a | a | a | b | c | c | c | c | d | e | |||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Bytes | 15 | 27 | 00 | 00 | 2A | 00 | 00 | 00 | 00 | 00 | 28 | C1 | 00 | 01 | 00 | 00 |
Note how there are gaps in the middle and at the end - this is called "padding". The data in this padding is undefined memory, and won't always be zero.
As our x
value is that of an extern struct, we could safely pass it into a C
function expecting a Data
, providing the C function was also compiled with the
same gnu
ABI and CPU arch.