Alignment and struct inheritance
I’m new to Zig, and working through the “Crafting Interpreters” book ATM.
I was/am struggling with the “struct inheritance”, where the type Obj
is just an enum and the (first of a handful) of actual object types uses this as the first field type
in the struct. The C ABI, as the author says, grants the memory of the struct so that casting pointers is easy.
In Zig, we have to use @parentFieldPtr
to downcast a *Obj
to a *ObjString
.
OK, I understand this (though it took me some time).
However, I’m not sure if I understand the alignment.
Note: Until now, my Obj
type does not yet contain the next
attribute (I’m just before chapter 19.5 “Freeing Objects”).
Without an ‘@aligncast’, the Zig compiler complains about alignment:
pub const ObjType = enum(u4) {
STRING,
};
pub const Obj = struct {
typ: ObjType,
// Some methods, but no other fields yet
}
pub const ObjString = struct {
obj: Obj,
length: u32,
chars: [*:0]const u8, // This is a variable length 0-terminated C string.
pub fn asObj(self: *ObjString) ObjPtr {
return &self.obj;
}
pub fn fromObj(o: *Obj) *ObjString {
std.debug.assert(o.typ == .STRING);
const s: *ObjString = @fieldParentPtr("obj", o);
return s;
}
...
}
@fieldParentPtr increases pointer alignment
‘*align(1) object.ObjString’ has alignment ‘1’
‘*object.ObjString’ has alignment ‘8’
@fieldParentPtr(“obj”, o)
I can solve this in two ways (or are there better ideas?):
I could explicitly use u64
instead of u4
for the enum.
But that wastes 7 bytes of memory for each object, so that’s for sure not the right solution.
Or I could use an @alignCast
together with @fieldParentPtr
, as @Southporter did in the generic as
function in line 59 of zlox/src/Object.zig at master · Southporter/zlox · GitHub
What exactly are the consequences of an @aligncast
here?
AFAIK an @aligncast
is a promise I give to the compiler.
Does this impose a risk that the correctness depends on the actual memory layout of the ObjString
struct?
When I continue working, the other object “subtypes” , e.g for functions, will contain obj: ObjType
field as the first field, too.
Is this construct safe?
What is considered best practice in cases like this?