Hello (Zig) World!
since I'm still not automatically remembering all the various combinatorial possibilities of different types of pointers, slices, const
ness and optionals, I've finally taken the plunge and created a little cheatsheet for quick reference. It's not exhaustive, but should cover most real world cases... nobody said it'd be easy! :)
const Cheatsheet = struct {
/// single u8 value
a: u8,
/// single optional u8 value
b: ?u8,
/// array of 2 u8 values
c: [2]u8,
/// zero-terminated array of 2 u8 values
d: [2:0]u8,
/// slice of u8 values
e: []u8,
/// slice of optional u8 values
f: []?u8,
/// optional slice of u8 values
g: ?[]u8,
/// pointer to u8 value
h: *u8,
/// pointer to optional u8 value
i: *?u8,
/// optional pointer to u8 value
j: ?*u8,
/// pointer to immutable u8 value
k: *const u8,
/// pointer to immutable optional u8 value
l: *const ?u8,
/// optional pointer to immutable u8 value
m: ?*const u8,
/// pointer to multiple u8 values
n: [*]u8,
/// pointer to multiple zero-terminated u8 values
o: [*:0]u8,
/// array of 2 u8 pointers
p: [2]*u8,
/// pointer to array of 2 u8 values
q: *[2]u8,
/// pointer to zero-terminated array of 2 u8 values
r: *[2:0]u8,
/// pointer to immutable array of 2 u8 values
s: *const [2]u8,
/// pointer to slice of immutable u8 values
t: *[]const u8,
/// slice of pointers to u8 values
u: []*u8,
/// slice of pointers to immutable u8 values
v: []*const u8,
/// pointer to slice of pointers to immutable optional u8 values
w: *[]*const ?u8,
};
Extern struct limitations
In extern struct
s optionals can only be used if in pointer-like form (but not directly for optional values), i.e. the following cases are all fine:
?*u8
*?u8
*const ?u8
?*const u8
[]?u8
[]const ?u8
On the other hand, a plain ?u8
field isn't allowed in extern structs...
Top comments (10)
Pointers, slices and arrays definitely have a very compact set of symbols that can be hard to remember. In my mind this makes sense because that's one of the abstract entities that lower-level programming requires you to manipulate with agility, not too differently from how physicists use "compact" symbols for the abstract concepts they need to manipulate efficiently.
One thing that I haven't done yet, but that I plan to do in sooner or later, is a post about when and how Zig ensures the presence of a sentinel, and when you have to do it yourself.
Thanks, Loris! I generally have zero issues with the syntax elements on their own, just often still not sure about the correct order (and the resulting semantics). Seeing the variations side by side really clarified things for me and maybe for others too...
Btw. Keeping an eye out for that sentinel post, sounds intriguing! So far I'm fine knowing strings are zero-terminated (in addition to being slices by default) and I'm also supporting both facts in my WASM/JS interop/codegen project (thi.ng/wasm-api)
The hard part for me is not decoding these, but converting between them. The zig compiler tells me what i have and what I need, but does not give any hint on how to convert them.
I would love to see a cheatsheet for that.
Yes, same boat! :) ...and that's a great idea for cheatsheet! (even though my hunch is that answers for these issues are very context sensitive and maybe need a different format, maybe not... 🤷)
In the extern struct examples, isn’t the second example a non-optional pointer? (to an optional u8)
IIUC, it does not meet the requirement for pointers to be optional
Maybe slightly unclear wording from my side on that extern section! I meant to say: optionals are only supported if in pointer form, but not as optional values, i.e.
*?u8
or?*u8
is supported, but?u8
isn't. That didn't mean to imply that all pointers must be optional! Normal pointers are supported of course... Makes sense?What is the logic behind this restriction? Something about the representation of non-pointer optionals?
I'd think it's because there's no concept of optional values in C, yet optional pointers can be represented in the same amount of space (using
0
as indicator for anull
pointer), whereas optional non-pointer values take up extra bytes, e.g. a?u8
is actually 2 bytes, a?u16
is 4 bytes, a?u32
is 8 bytes...An argument could be made that by that logic slices shouldn't be supported either (but they are), so I really don't know the reasons... :)
Just edited that section of the post, hopefully clarifying things... Thanks for pointing it out!
nice post! could
[*c]T
be added?