#literal [*:null]const ?[*:0]const u8

1 messages · Page 1 of 1 (latest)

obsidian sandal
#

specifically the interior const doesnt appear to be actually allowed. ```
/home/aep/kram/hello-world/src/main.zig:15:41: error: pointer modifier 'const' not allowed on array child type
std.os.execveZ("/bin/ls", &[_:0]const u8{ "/bin/ls", null }, null);
^~~~~

icy terrace
#

alright, so let's deconstruct this

#

[_]T{...} is an array literal. Arrays and array literals don't have qualifiers, because they're not pointers

#

the literal you're constructing isn't valid here in the first place either though, because what you want to pass is a pointer of pointers

#

and what [_:0]u8 is just an array of u8s

#

Thus, what you'd want is &[_:null]?[*:0]const u8{...}, which means "a null-terminated array of optional [*:0]const u8s"

#

the type of that expression is actually *const [n:null]?[*:0]const u8, but it just so happens that pointers to arrays coerce to slices and multi pointers, and thus it'll coerce to [*:null]const ?[*:0]const u8

obsidian sandal
#

uh wow. that's a lot to digest.

#

nope i still dont get it. where can i read more about the syntax or arrays?

icy terrace
#

I'd start at the documentation

obsidian sandal
#

right, i did read that one but was hoping for something less dense

icy terrace
#

well, then let me try to rephrase

willow egret
icy terrace
#

[_]T{...} is an array of Ts.
[_:s]T{...} is a sentinel-terminated array of Ts, with the sentinel being s (which must be a valid value of type T).
Note that T can be any sized type, whether that be a simple integer like u8, or a more complex type like a pointer, e.g. []const u8, [*:0]i32, etc. Those are best learned aside from arrays.

In zig, arrays are treated as first class values, as opposed to C where they decay to pointers. That is to say, given an expression a = b, assuming these are arrays of the same type, the whole value of b will be copied into a. And much like other values, you can have pointers to arrays - that is, a pointer to [3]T is written *[3]T. Simple.

Now, pointers to arrays have some special properties, namely that they have some special coercion rules that make them easier to work with when inter-oping with pointers that don't have a comptime-known number of items.
For example, much like an i32 can coerce to a i64 without any special casting, *[3]u8 can coerce to []u8 or to [*]u8 without any special casting - so long as the qualifiers of the pointers are compatible. E.g., you're not allowed to cast from *const u16 to *u16, and you're also not allowed to cast from *const [3]T to []T - since you'd be discarding the const qualifier.

Given all that, it should now be noted that there aren't any slice or many-item-pointer literals in zig. As such, what we instead do is take pointers to array literals, which will coerce to both slices and many-item pointers. So what the expression &[_]T{...} does is say "declare this array literal, and take its address".

#

wrt to coercion rules, there is more to it, but it's not too much more nuanced

#

the general rule is "you can't coerce pointer A to pointer B if A has qualifiers that B doesn't"

wispy condor
#

what rule(s?) disallow the &.{} syntax?

icy terrace
#

none, just trying to explain the basic mechanics

#

'cause tuple pointers are then another rule that builds off of those basic mechanics, but in a funky kind of way

wispy condor
#

well it doesnt like when i try to do that with that function

icy terrace
#

does it not work?

wispy condor
#

no

icy terrace
#

weird.

#

probably the compiler just isn't figuring out the coercion

wispy condor
#

note: a single pointer cannot cast into a many pointer

icy terrace
#

or maybe it's intentional that tuple pointers can't coerce to multi pointers, hard to say

wispy condor
obsidian sandal
#

so uhh. you sayd coercion between sized and unsized should work

#

'[*:null]?[*:0]const u8', found '[2:null]?[*:0]const u8'

icy terrace
#

need to make sure you take its address

obsidian sandal
#

these are the same types arent they?

icy terrace
#

arrays don't coerce implicitly

#

pointers to arrays do

obsidian sandal
#

i tried that, but then

#

apparantly & turns it into *const [2...

#

instead of into [*

icy terrace
#

yes, and that ought to coerce

#

oh wait

#

I think I see the issue

#

it won't accept a literal

obsidian sandal
#

oh

icy terrace
#

see, the point about const vs non-const is important

#

it's expecting []T essentially

#

whilst *const [2]T would only coerce into []const T

#

so you'll have to declare a mutable array variable, and pass a pointer to that

obsidian sandal
#
 28     const argv = [_:null]cstring{ "/bin/bash", null };                 
 29     const bash = Unit{ .argv = &argv };       
icy terrace
#

ye

obsidian sandal
#
/home/aep/kram/hello-world/src/main.zig:29:32: error: expected type '[*:null]?[*:0]const u8', found '*const [2:null]?[*:0]const u8'
    const bash = Unit{ .argv = &argv };
                               ^~~~~
icy terrace
#

make that var argv

obsidian sandal
#

oh mutable

#

that worked. i guess i should declare the field in the struct const tho

icy terrace
#

ye

#

most likely

#

I was about to ask whether you wrote that

obsidian sandal
#
  4 const Unit = struct {      
  5     argv: [*:null]cstring,                                                                                                                                                
  6     envp: [*:null]cstring,      
  7 };                           
#

so yeah

#

uuh apparantly you cant make them const?

icy terrace
#

[*:null]const cstring

obsidian sandal
#

uuhhh wow thats confusing

wispy condor
icy terrace
obsidian sandal
#

works fine now tho, including literal

icy terrace
#

an integer is an integer, regardless of whether it's mutable or immutable

obsidian sandal
icy terrace
#

that isn't the memory location

obsidian sandal
#

i feel like the right hand side of the array thingy should be the type?

icy terrace
#

that is the field which holds the pointer value

obsidian sandal
#

right

icy terrace
#

the pointer determines whether the pointed-to memory is const or mutable

obsidian sandal
#

but then its part of the pointer type 😄

#

anyway, i'll get used to it

icy terrace
#

e.g., with a variable, you can have any combination of

var a: []T
var b: []const T
const c: []T
const d: []const T
#

the variable may be mutable or const, but that has no bearing on whether the pointed-to memory is const or non-const

obsidian sandal
#

that makes sense

#

also it appears to be consistent. i dont have a particular strong feeling as long as its consistent