I stumbled on something that made me understand the extent of variable recycling:
in a function, I have a Unicode treatment, which I transform with:
vUnicode = [_]u8{0} ** 4;
var i = utf.utf8Encode(c0,&vUnicode) catch unreachable;
Event.Key = kbd.char;
Event.Char = vUnicode[0..i];
I noticed that if the declaration of vUnicode was in a function, I lost Event.char even if it is in return Event
In fact, it was like a switch from vUnicode and when closing by function was destroying the reference to that variable and causing inaccessibilityā¦
To overcome this problem, I put the variable at the top outside of the functions in the module.zig
there in the program
or I use the import of the module
indeed, I do not lose the value
Apart from my observation and taking into account the operation of Zig-lang
did I understand right ???
Yes, I think you are getting the right idea that the address of variables declared by a function should no longer be accessed after that function returns. This is because such variables are allocated on the stack, and after the function returns that portion of the stack is reused by other functions, so its contents are overwritten.
This concept is not Zig-specific. In general these are called automatic variables and you can read more about them here:
You can also google for āstack variablesā and find many explanations, videos, etc, hopefully some in your native language (I assume it is not English, but please excuse me if Iām incorrect).
I see now that you have lots of programming experience so you probably know what an automatic variable is. So what you may have been missing about Zig is:
An array such as vUnicode, declared as a local/automatic variable, is stack allocated in Zig, not heap allocated.
The Zig compiler does not detect when a local variable memory address escapes its scope ā for example, when it is returned by the function or is stored in the field of a longer lived struct. Zig, relies on the programmer to avoid this. If the programmer does it, bad things will happen (undefined behavior) as you experienced.
Yes, I understand perfectly, but I used a other language where the purge was done after the settings were returned.
var x = function();
good itās a good thing to understand how it works and to get to the top.
In this case it was a variable which it was worth in āglobalā and not do an āallocā function used in the keyboard read function then a defer
int *return_lva(void)
{
int x;
return &x;
}
#include <stdio.h>
int main(void)
{
int *xp = return_lva();
printf("xp = %p\n", xp);
}
gcc (9.4.0) warns (at least) about this, even without -Wall:
$ gcc lva.c
lva.c: In function āreturn_lvaā:
lva.c:5:12: warning: function returns address of local variable [-Wreturn-local-addr]
5 | return &x;
| ^~
Iām not sure under what conditions C can warn about escaping local addresses, but I removed the ālike Cā in that sentence. This discussion isnāt about C, after all.
I would be careful with the global variable solution. Given code like this:
var buf: [4]u8 = undefined;
fn iota(start: u8) []u8 {
var i: u8 = start;
while (i -% start < buf.len) : (i +%= 1) {
buf[i -% start] = i;
}
return buf[0..];
}
test {
const a = iota(0);
const b = iota(1);
try std.testing.expect(!std.mem.eql(u8, a, b));
}
running zig test on it will show you that it fails, because in both cases the return value points at the same global memory. In cases where you need each return value to be independent of the other, it is a good idea either to accept an std.mem.Allocator parameter in order to allocate memory for the result, or accept an output buffer.
Instead of using a global you could declare it in the enclosing function scope that defines its lifetime, main if nothing else, and then pass a pointer down to the function that needs it.