Help understanding optionals paired with pointers

I need help understanding the semantics of optionals paired with pointers.

Let’s say we have the following cases:

?i32 // <-- Int that may not exist
*?i32 // <-- Pointer to int that may not exist
?*?i32 // <-- Pointer that may not exist to an int that may not exist
*?*?i32 // <-- Pointer to pointer that may not exist pointing to an int that may not exist

My main confusion is how do these map to C ABI?

Is ?*i32 the same as *?i32 when considering *int?

No, these are 2 separate types with different semantics. ?*i32 will be the closest to int * in C. Since C pointers can be null, you want the Zig type where the pointer can be null, which in this case is ?*T.

Although possible I would not recommend this :slight_smile:
But maybe there are usecases imaginable?

btw *?c_int is not technically compatible with the C ABI.

my limited understanding is that ?c_int is currently implemented a bit like

struct {
    inhabited: bool,
    payload: c_int,
};

and thus that, like all non-extern, non-packed structs, the layout of ?c_int is not considered well-defined (= part of an ABI contract that will be honored by different versions of the zig compiler or even across different compilation units in a single invocation of zig build)

3 Likes

Just for clarification, types should be read left-to-right:

?i32 // <-- optional i32
*?i32 // <-- pointer to an optional i32
?*?i32 // <-- optional (pointer to an optional i32)
*?*?i32 // <-- pointer to an optional (pointer to an optional i32)

So, as mentioned, for an optional pointer, you want ?*i32 (relevant section of the language reference)

3 Likes