#typecast []u8 arra to [64]u8 array
1 messages · Page 1 of 1 (latest)
you can re-slice the slice with comptime known values, and deref that:
foo[0..64].*
I will try that
Thank you
It worked
Why do I have to do like that
Any explanations?
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
dereferencing slices is such a nice feature
you can't deref a slice, you can only deref a pointer to a single item - that single item could be an array though.
I see
var slice = try std.heap.page_allocator.alloc(u8, 8);
@memcpy(slice, &[_]u8{ 0, 1, 2, 3, 4, 5, 6, 7 });
const array2: [4]u8 = slice[3..7].*;
print("{any}\n", .{array2});
prints { 3, 4, 5, 6 }
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
Thank you
gethostname is defined to have a maximum number of bytes that it will write to the output buffer, and so the parameter encodes that with a pointer to an array.
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.
oh okay okay
that should make it easier to use it but yeah as long it works its fine
for now
You'll find that the hashing functions do something similar because they too only generally yield a fixed-size result.
There is some merit to that yeah - though, at the same time, you're creating the potential for a bug by virtue of making it a runtime check that will crash your program, or creating a check that you know will always pass.
got it that was really helpful
thank you
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
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
defer alloc.free(sent_str);
@memcpy(sent_str, self.host_name);
const h_name: ?[*:0]const u8 = @ptrCast(sent_str);
std.debug.print("\n{s}\n", .{h_name.?});``` this does work any changed needed to be done?
oh got it so the array length does change if we use sentinal terminated string?
like + 1 due to string is 0 terminated correct me If I am wrong
no need for the @ptrCast. a @ptrCast is used to change a pointer's child type. you only need to access the ptr field, to get [*:0]const u8, that will further coerce into an optional.
const h_name: ?[0:*]const u8 = sent_str.ptr;
I will change that
yes. a sentinel array / slice of .len n holds / points to n + 1 elements, the last one being the sentinel.
yes Sir thank you for your guidance
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
to check whether the thats end of the array?
like here 0 is the end
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
Yeah basically I can store even 1000 variables by using [:0] u8 but it will be less efficient to [1000:0] u8
Makes a lot of sense now
wait wha?
explain further... I think you're misunderstanding how arrays and slices work.
also, what other programming languages do you know? I think some of the concepts may have been lost in translation
It’s python and rust🙂↕️🙂↕️
I never used sentinel string in rust
Trying to learn zig and c together tho
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
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
it doesn't exist in Rust - that's the interesting bit...
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
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
Yeah that allows me to learn new concepts tho
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
-# 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.
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
Yeah Comptime is actually awesome
Just one small request here can you just write how I can store pointer part of slices
I actually started to like zig when I was able to do some many stuff with it’s actually fun not like my college lecture on Java and OOP
sure, here is the unoptimised version, needlessly storing two slices (the slices' child types are both u8):
const SlicePair = struct {
a: []u8,
b: []u8,
};
and here is the optiomised, thinner version:
const SlicePair = struct {
a: [*]u8, // has self.len elements
b: [*]u8, // has self.len elements
len: usize,
};
Thank you I will surely use it
to get the pointer out of a slice, simply do slice.ptr. to get the length use slice.len
Oh so it will return to the first slice ?
OOP...
my condolences. stay strong.
It was 5 years back
the pointer inside a slice points at the the first item in the sequence
the effects of OOP are long lasting, some people never recover... :P
Yeah so I can add the current_pos + length- current_pos to get the pointer of second Slice
Yee thanks good sir
For taking ur time
All my Frnds have long gone lost within it
slice in my message of accessing its fields is a value of type []T, or []const T, or [:sen]T, or... you get the point.
are you asking about recovering the slices out of a value of the optimised SlicePair?
Yes from slice pair
ah. lemme code it up real quick...
You have a lot of knowledge tho
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];
}
};
I am what people sometimes call, "a nerd"
You are a cool person
Thank you
o7