#typecast []u8 arra to [64]u8 array

1 messages · Page 1 of 1 (latest)

tulip basin
#
pub fn gethostname(name_buffer: *[HOST_NAME_MAX]u8) GetHostNameError![]u8 {```
sage hill
#

you can re-slice the slice with comptime known values, and deref that:
foo[0..64].*

tulip basin
#

It worked

#

Why do I have to do like that

#

Any explanations?

sage hill
#

arrays, pointers to arrays, and slices can all be sliced using x[y..z] notation, yielding you a slice into x, starting at index y up to index z (exclusive).

if both y and z are values known at compile time it'd be a waste to return a slice, since we know what its length is going to be - in that case Zig returns a pointer to an array, the array's length being z - y.

so foo[0..64] returns us a *[64]T (where T is foo's child type). we then dereference the pointer (this is a pointer to a single item, so we are able to do that), to get a value of type [64]T.

for further reading, look into arrays and slices in the language reference

dull solstice
#

dereferencing slices is such a nice feature

sage hill
dull solstice
#

I see

dull solstice
sage hill
#

yes, but you're never derefing a slice here. you're derefing a *[4]u8

#

the slicing operation yields a pointer-to-array, because both bounds are comptime known

dull solstice
#

ok that makes sense

#

thanks

signal sequoia
#

It could just take a []u8 and do assert(buffer.len >= 64);, but now it's a runtime check instead of a static one.

#

Not to say Zig couldn't have static analysis to help promote that check to be static, but it doesn't do stuff like that.

tulip basin
#

for now

signal sequoia
signal sequoia
tulip basin
#

thank you

tulip basin
#

and is there a way to type cast a []const u8 into [*:0]const u8

#

there are lot of variants of arrays

#

thread 12704 panic: sentinel mismatch: expected 0, found 109
C:\Users\dovak\browser\src\main.zig:94:54: 0xe035cc in request (browser.exe.obj)
const h_name: ?[*:0]const u8 = self.host_name[0 .. self.host_name.len - 1 :0].ptr;

#

this what I am getting

sage hill
#

you're trying to convert a slice (a pointer + length pair) of constant u8s into a pointer-to-many (just a pointer, this type does not hold length information!) u8s, with a sentinel value 0 - so, you guarantee there is a 0 value past the last index of the slice you're making.

this conversion cannot happen as is. when you try to create a sentinel-terminated slice Zig runtime safety checks (in checked build modes) ensure that there really is the sentinel that you specified at the end.

there isn't one - so the program crashed. (hooray! you've just caught a bug!)

in the general case you'll have to allocate new memory (look into the allocSentinel method on std.mem.Allocator), though in many situations you need not resort to dynamic memory

tulip basin
tulip basin
#

like + 1 due to string is 0 terminated correct me If I am wrong

sage hill
sage hill
tulip basin
sage hill
#

a pointer to many items with a sentinel value ([*:sen]Type) points to an unknown number of elements, after which there is a guaranteed sentinel value

tulip basin
#

like here 0 is the end

sage hill
#

a pointer-to-many with a sentinel is a way to encode within the type system the fact that a sequence has a sentinel value at the end. this is useful for cases where you'd rather store information about the sequence's end inside of the sequence, rather than the more common (and most time better) approach of holding the length information alongside the pointer to the sequence.
-# boy do I love type safety

tulip basin
#

Makes a lot of sense now

sage hill
tulip basin
#

I never used sentinel string in rust

#

Trying to learn zig and c together tho

sage hill
#

ah. if you know Rust you should know most things.
an array in Zig ([N]T) is like an array in Rust ([T; N])
a pointer-to-single in Zig (*const T. *T) is like a reference in Rust (&T, &mut T); except Rust has nice lifetime and aliasing checks - note that in Zig, mutable is the default (sadly)
a slice in Zig ([]const T, []T) is like a slice in Rust (&[T], &mut [T])

now... pointers-to-many items and sentinels don't really exist in Rust, and they are a bit weirder
-# why have I got myself into this?? now I need to write a follow-up message >_< and I was in the middle of eating a cake

tulip basin
#

Yeah I was able to understand that part I am getting mixed up with strings and slices

#

Oh sorry for disturbing you

#

U can eat ur cake

#

😅

#

Yeah I never encountered pointer to many in Rust and that concept is new to me

sage hill
tulip basin
#

It’s unsafe part

#

I never went into it

#

Like it should be possible

#

But only in unsafe rust

#

Or it doesn’t exist at all I never went into that part tho

sage hill
#

I believe Rust has that ability in the form of raw pointers, but Rust (sadly!) does not distinguish between a pointer-to-one and a pointer-to-many in its type system. Zig operates much better in this regard

tulip basin
#

Zig kinda makes me go under the hood

#

Even tho allocators are in rust I never used them at all here I am always using them this allows me to explore more concepts

sage hill
# sage hill ah. if you know Rust you should know most things. an array in Zig (`[N]T`) is li...

-# follow up message, I have finished the cake
Zig can encode a pointer to many items, without the extra length data. you may know that in Rust &[T] is a fat pointer, because it holds extra info about the pointed data (in this case, its length)

usually pointers-to-many are not used; but they are useful in some cases:
suppose you have a struct that holds two slices, and because of some invariant you know for certain that those two slices have the same length - always.
it'd be a shame to store two slices, since both lengths are always equal, this is a waste of a space! instead, we can store just the pointer part of the slices, with the length stored somewhere else - we've just saved @sizeOf(usize) bytes!

sometimes, for any number of reasons, we'd like to store a sequence of items, and remember its length not with an associated length data, but in a way that is embedded inside the sequence.

one such approach, common in C, and supported by Zig's type system, is sentinel values.

a sentinel value is a special value that we've decided on, that is situated at the end of the sequence - it "guards" the end of the sequence: once we encounter it we know the sequence is over (hence the name sentinel).

in Zig we can encode the sentinel within the type, with the :sen syntax.

it's sometimes nice, most times unneeded.

sage hill
# tulip basin Yeah that allows me to learn new concepts tho

the more languages you know, the better.
Zig has two things it excels at, in terms of knowledge sources:

  • it's unapologetically low-level. below Zig there's only assembly (yes. I think C is higher-level than Zig, even though programming in Zig is a lot nicer)
  • comptime. you don't really see this concept anywhere else, and it's mind-blowing
tulip basin
tulip basin
tulip basin
sage hill
tulip basin
sage hill
#

to get the pointer out of a slice, simply do slice.ptr. to get the length use slice.len

tulip basin
sage hill
tulip basin
sage hill
sage hill
tulip basin
#

Yee thanks good sir

#

For taking ur time

tulip basin
sage hill
sage hill
#

ah. lemme code it up real quick...

tulip basin
#

You have a lot of knowledge tho

sage hill
#

unoptimised version, implementation is trivial.

const SlicePair = struct {
    a: []u8,
    b: []u8,

    fn gimmeA(self: SlicePair) []u8 {
        return self.a;
    }

    fn gimmeB(self: SlicePair) []u8 {
        return self.b;
    }
};

optimised version

const SlicePair = struct {
    a: [*]u8,
    b: [*]u8,
    len: usize,

    fn gimmeA(self: SlicePair) []u8 {
        // reslice the pointer-to-many to get back a slice
        return self.a[0..self.len];
    }

    fn gimmeB(self: SlicePair) []u8 {
        return self.b[0..self.len];
    }
};
sage hill
tulip basin
signal sequoia