Zig NEWS

Karsten Schmidt
Karsten Schmidt

Posted on • Updated on

Type/pointer cheatsheet

Hello (Zig) World!

since I'm still not automatically remembering all the various combinatorial possibilities of different types of pointers, slices, constness 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,
};
Enter fullscreen mode Exit fullscreen mode

Extern struct limitations

In extern structs 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...

Discussion (10)

Collapse
kristoff profile image
Loris Cro

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.

Collapse
toxi profile image
Karsten Schmidt Author • Edited on

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)

Collapse
orent profile image
orent

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

Collapse
toxi profile image
Karsten Schmidt Author

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?

Collapse
orent profile image
orent

What is the logic behind this restriction? Something about the representation of non-pointer optionals?

Thread Thread
toxi profile image
Karsten Schmidt Author

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 a null 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... :)

Collapse
toxi profile image
Karsten Schmidt Author

Just edited that section of the post, hopefully clarifying things... Thanks for pointing it out!

Collapse
voroskoi profile image
voroskoi

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.

Collapse
toxi profile image
Karsten Schmidt Author

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... 🤷)

Collapse
haoliang profile image
haoliang

nice post! could [*c]T be added?