Loop, 2 func() func() { ; Note no static bugvar! static switchvar = 0 if switchvar { ; Make the variable show its hidden contents NumPut(Asc("H"), bugvar, 0, "UChar") MsgBox % bugvar }else ; This function was ran for the first time { ; Initialize the variable bugvar = _idden variable contents reappear! switchvar = 1 } }
Funny local variable behavior
Same here.I get a blank message box (running the latest AHK version).
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Antonio França -- git.io -- github.com -- ahk4.net -- sites.google.com -- ahkscript.org
Member of the AHK community since 08/Apr/2009. Moderator since mid-2012.
:|A future version of AutoHotkey might make this behavior the default.
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Antonio França -- git.io -- github.com -- ahk4.net -- sites.google.com -- ahkscript.org
Member of the AHK community since 08/Apr/2009. Moderator since mid-2012.
#NoEnv gVar=_idden va0iable con0ents reap0ear!56789012345678901234567890123 VarSetCapacity(gVar,0) NumPut(Asc("H"),gVar,0,"UChar") MsgBox % gvarFor all (OK, most) practical purposes, the variable does not exist when you use it again. The string length is zero and if you test the variable, i.e. If MyVariable, it will test as False. All string commands such as StringLeft, StringLower StringMid, etc. are not affected.
Them be my thoughts...
I think.
Edit:
"All string commands such as StringLeft, StringLower StringMid, etc. are not affected."
This, too can be explained by the fact that ahk keeps a separate record of the length of the string in a given variable, which is set to 0 when cleared. All the string commands refer to this value for validating values, which can save it a lot of time vs going through the entire string to find the null char every time someone uses a string command.
If #NoEnv is not present, AutoHotkey looks for an environment variable when the variable's internal "length" field is 0. Even if there is no environment variable, it does not use the variable's actual contents in that case. #NoEnv itself is not in any way responsible for the effect demonstarted by fincs and jballi.It's the #NoEnv directive that's causing this to happen
OT: #NoEnv is important for performance because without it, every time you evaluate an empty variable, the script has to search for an environment variable by the same name. Even having this mechanism present (with or without #NoEnv) negatively affects performance of all scripts, though perhaps not noticably.
Just look at this case (I only want it to be documented!):What do you want to happen when you use NumPut on an "uninitialized" variable? Variables are not guaranteed to be zero-initialized unless you specifically do it yourself.
DecodeBase64(data){ DllCall("crypt32\CryptStringToBinaryA", "uint", &data, "uint", 0, "uint", 1, "uint", 0, "uint*", len, "uint", 0, "uint", 0) VarSetCapacity(d_data, len) DllCall("crypt32\CryptStringToBinaryA", "uint", &data, "uint", 0, "uint", 1, "str", d_data, "uint*", len, "uint", 0, "uint", 0) ; This function doesn't work properly if you don't uncomment the NumPut() line. ; The scripter may be puzzled to see remnants from the last function result if ; the base64-encoded data doesn't contain a termination NULL (the most common case): ;NumPut(0, d_data, len, "UChar") return d_data }
"All local variables start of blank each time the function is called," but this only means a null-terminator is set at the beginning of the variable. Any content following the null-terminator is initially undefined, so relying on its value is asking for trouble. Documenting that local variables might "retain" their contents between calls would be counterproductive since the contents are still undefined in other situations.
On the other hand, it might be worth clarifying how variables are "initialized". VarSetCapacity hints at it:
Local variables are freed or cleared when the function returns in the same way as VarSetCapacity(var,0), so the following applies:FillByte: This parameter is normally omitted, in which case the memory of the target variable is not initialized (instead, the variable is simply made blank as described above).
However, it only might have no effect, so you can't rely on it. If d_data extends beyond 63 bytes, it becomes non-permanent and will be freed when the function returns. Undocumented: In all subsequent calls it will receive non-permanent memory. VarSetCapacity will allocate exactly the length requested (plus 1) and will null-terminate in the correct position every time. This behaviour can be forced:For performance reasons, freeing a variable whose previous capacity was between 1 and 63 might have no effect because its memory is of a permanent type.
DecodeBase64(data){ static s if !s ; To demonstrate it only needs to be done once. s := VarSetCapacity(d_data,64), VarSetCapacity(d_data,0) ... }Btw, even if the variable's contents are freed, there's no guarantee that the same memory won't be allocated to that variable (or a different variable) at some later point. A variable could hypothetically even be allocated different memory with contents identical to what it had previously.