🎓 A1Learner
🔍
0 of 46 lessons completed

Zig Extern Types

An extern type is a struct or union whose layout follows the C layout rules. It lets Zig data match data shared with C code.

Extern layout

The fields stay in declaration order. Padding moves the u32 field to offset 4.

const std = @import("std");
const Ext = extern struct {
    a: u8,
    b: u32,
    c: u8,
};
pub fn main() !void {
    const out = std.io.getStdOut().writer();
    try out.print("ext size={d} align={d} off a={d} b={d} c={d}\n", .{ @sizeOf(Ext), @alignOf(Ext), @offsetOf(Ext, "a"), @offsetOf(Ext, "b"), @offsetOf(Ext, "c") });
}

Plain against extern

The plain struct reorders fields to save space. The extern struct does not reorder, so C code can rely on its layout.

const std = @import("std");
const Reg = struct {
    a: u8,
    b: u32,
    c: u8,
};
pub fn main() !void {
    const out = std.io.getStdOut().writer();
    try out.print("plain size={d} align={d} off a={d} b={d} c={d}\n", .{ @sizeOf(Reg), @alignOf(Reg), @offsetOf(Reg, "a"), @offsetOf(Reg, "b"), @offsetOf(Reg, "c") });
}

Shared storage

All union fields share the same storage. The same bits read as an integer or as a float.

const std = @import("std");
const EU = extern union {
    i: i32,
    f: f32,
};
pub fn main() !void {
    const out = std.io.getStdOut().writer();
    try out.print("eu size={d} align={d}\n", .{ @sizeOf(EU), @alignOf(EU) });
    const u = EU{ .i = 1065353216 };
    try out.print("eu i={d} f={d}\n", .{ u.i, u.f });
}

Example

const std = @import("std");
const Header = extern struct {
    kind: u8,
    value: u32,
};
const Bits = extern union {
    i: i32,
    f: f32,
};
pub fn main() !void {
    const out = std.io.getStdOut().writer();
    try out.print("header size={d} off kind={d} value={d}\n", .{ @sizeOf(Header), @offsetOf(Header, "kind"), @offsetOf(Header, "value") });
    const bits = Bits{ .f = 1.5 };
    const as_int: u32 = @bitCast(bits);
    try out.print("bits={d}\n", .{as_int});
}

Key points

  • Extern struct: an extern struct is a struct declared with extern, whose fields stay in declaration order with C padding.
  • Extern union: an extern union is a union declared with extern, whose fields all start at offset zero.
  • Offset: an offset is the distance in bytes from the start of a struct to a field.
  • Alignment: alignment is the address multiple a field must start on, and it decides where padding goes.
  • A plain struct may reorder its fields to save space, while an extern struct keeps declaration order.
  • The size of an extern struct counts its padding, so it can be larger than the plain version.

The header keeps declaration order with padding before the wide field. The union holds one value in two forms. The bit pattern of 1.5 is the same integer in both views.

Try it Yourself

Edit the code, then press Run.

Running is simulated

Exercise

An extern struct has a: u8 then b: u32. What is the offset of b?