Extended Variable DeclarationsVariables can be declared in more ways than simply new.
decl PurposeBy default, all variables in Pawn are initialized to zero. If there is an explicit initializer, the variable is initialized to the expression after the = token. At a local scope, this can be a run-time expense. The decl keyword (which is only valid at local scope) was introduced to let users decide if they want variables initialized or not.
Note: decl should not be used on single cell variables. There is almost never any benefit.
ExplanationFor example:
new c =
5;
new d;
new String:blah
[512];
Format(blah, sizeof
(blah
),
"%d %d", c, d
);[/pre]In this code, c is equal to 5 and d is equal to 0. The run-time expense of this initialization is negligible. However, blah is a large array, and the expense of initializing the entire array to 0s could be detrimental in certain situations.
Note that blah does not need to be zeroed. In between being declared with new and stored with Format(), blah is never loaded or read. Thus this code would be more efficiently written as:
new c =
5;
new d;decl String:blah
[512];
Format(blah, sizeof
(blah
),
"%d %d", c, d
);[/pre]
CaveatsThe downside to decl is that it means its variables will start with "garbage" contents. For example, if we were to use:
new c =
5;
new d;decl String:blah
[512]; PrintToServer
("%s", blah
);
Format(blah, sizeof
(blah
),
"%d %d", c, d
);[/pre]This code may crash the server, because blah may be completely corrupt (strings require a terminator, and that may not be present). Similarly, if we did:
new c =
5;decl d;decl String:blah
[512];
Format(blah, sizeof
(blah
),
"%d %d", c, d
);[/pre]The value of d is now undefined. It could be any value, negative or positive.
Note that it is easy to efficiently make strings safe. The example below shows how to terminate a garbage string:
decl String:blah
[512]; blah
[0] =
'\0';[/pre]
Golden Rules- Only use decl if in between declaring and loading/reading the value, you are absolutely sure there is at least one store/set operation that gives the variable valid data.
- Do not prematurely optimize. Likewise, there is no need to use decl on non-arrays, because there is no added expense for initializing a single cell value.
NotesThis example is NOT as efficient as a decl:
new String:blah
[512] =
"a";[/pre]Even though the string is only one character, the new operator guarantees the rest of the array will be zeroed as well.
Also note, it is valid to explicitly initialize a decl
ONLY with strings:
decl String:blah
[512] =
"a";[/pre]However, any other tag will fail to compile, because the purpose of decl is to avoid any initialization:
decl
Float:blah
[512] =
{1.0};[/pre]
staticThe static keyword is available at global and local scope. It has different meanings in each.
Global staticA global static variable can only be accessed from within the same file. For example:
//file1.incstatic Float:g_value1 =
0.15f;
//file2.incstatic Float:g_value2 =
0.15f;[/pre]If a plugin includes both of these files, it will not be able to use either g_value1 or g_value2. This is a simple information hiding mechanism, and is similar to declaring member variables as private in languages like C++, Java, or C#.
Local staticA local static variable is a global variable that is only visible from its local lexical scope. For example:
MyFunction
(inc
){ static counter =
-1; counter += inc;
return counter;
}[/pre]In this example, counter is technically a global variable -- it is initialized once to -1 and is never initialized again. It does not exist on the stack. That means each time MyFunction runs, the counter variable and its storage in memory is the same.
Take this example:
MyFunction
(5);MyFunction
(6);MyFunction
(10);[/pre]In this example, counter will be -1 + 5 + 6 + 10, or 20, because it persists beyond the frame of the function. Note this may pose problems for recursive functions: if your function may be recursive, then static is usually not a good idea unless your code is re-entrant.
The benefit of a local static variable is that you don't have to clutter your script with global variables. As long as the variable doesn't need to be read by another function, you can squirrel it inside the function and its persistence will be guaranteed.
Note that statics can exist in any local scope:
MyFunction
(inc
){ if (inc >
0) { static counter;
return (counter += inc
);
} return -1;
}[/pre]