DIM var[(subscripts)] [AS [GLOBAL | INSTANCE | LOCAL | STATIC | THREADED]type] [PTR | POINTER] [AT address] [, ...]
' var may include a type-specifier
DIM var AS [GLOBAL | INSTANCE | LOCAL | STATIC | THREADED] type [PTR |POINTER] [, ...]
DIM var ' var must include a type-specifier
DIM declares var to be a variable or array whose type is specified by appending a type-specifier to the name or by using the AS type keyword. If the AS clause is used, the variable name cannot end with a type-specifier character.
DIM can also be used to dimension an "absolute array" - one that occupies a specific location in memory. This can be useful to dynamically "superimpose" one type of array directly over the top of an existing block of memory (which could be another type of array, or data structure). This would form a Union-like overlay structure. See below.
In addition, it is possible to create an array of pointers with the DIM statement, and it is also possible to do so at a specific location in memory. This is termed an "absolute pointer array".
subscripts may take one of the following forms for each array dimensioned:
(a) A comma-delimited list of one or more Long-integer expressions, each defining a dimension of the array. This form is used to declare arrays whose subscript (index) range starts at 0. For example, the following lines are equivalent ways of dimensioning the same array:
DIM lArray(20) AS LONG ' With an AS type clause
DIM lArray&(20) ' With a type-specifier
Both lines above define a one dimension Long-integer
array that has 21 elements, from lArray(0) to lArray(20) inclusive.
The second line uses a type-specifier symbol to specify the
Declarations of multiple-dimension arrays take the following forms:
DIM sArray(20,40,2) AS STRING
These two lines of code define a dynamic string array with three dimensions, 21 elements by 41 elements by 3 elements, totaling 2583 string elements. As before, the second line uses the simplified syntax form.
(b) A comma-delimited list where both the upper and lower subscript bounds are explicitly declared for each dimension of the array. For each dimension, the lower bound is listed first, followed by the TO keyword, followed by the upper bound. For example:
DIM MyArray(1 TO 20) AS LONG
…defines an array of one dimension that has 20 elements, from MyArray(1) to MyArray(20). The lower bound does not have to be zero or one; for example:
DIM SalesByYear(1980 TO 2000) AS INTEGER
DIM SalesByYear%(1980 TO 2000)
Each array can access elements in the range of -2,147,483,648 to 2,147,483,647. It is recommended that an explicit variable scope clause (GLOBAL/LOCAL/STATIC) be added to each DIM statement that uses an explicit type clause. See Restrictions below.
Array Initialization and Absolute Arrays
PowerBASIC generates an error message when it encounters an array that hasn't been dimensioned. If the array has already been dimensioned, the DIM statement is ignored. A new array is not created and a run-time error is not generated.
When a program is first executed, PowerBASIC sets each element of a numeric array to zero, and sets each element of regular string arrays to a null string (length zero). However, when an absolute array is Dimensioned (at a specific location in memory using the AT address syntax), PowerBASIC does not initialize the memory occupied by the array. Further, when an absolute array is erased, the memory is not released either. This provides a powerful mechanism to create Union-like overlay structures in memory.
The most common use of an absolute array is when manipulating Visual Basic arrays directly from a DLL. This involves obtaining a pointer to the array, the element size, and the number of elements. With this information, an absolute array can be dimensioned in PowerBASIC and the array memory manipulated directly. Another common use involves using a large dynamic or fixed-length string memory block, overlaid with an absolute numeric array.
Care must be exercised when using absolute arrays, since the contents of an absolute array can only be valid for the scope of the memory the array references. If an absolute array references memory that is LOCAL to the procedure, the array contents become invalidated if the target memory block is released. For example, by either explicitly deallocating the memory block, or exiting the procedure itself. Attempting to access absolute array memory that has been deallocated will likely trigger a General Protection Fault (GPF). On this basis, absolute arrays should be LOCAL to the procedure in which they are to be used.
While PowerBASIC supports LBOUND values that are non-zero, PowerBASIC generates the most efficient code if the LBOUND parameter is omitted (i.e., the array uses the default LBOUND of zero). You should also avoid specifying an explicit LBOUND of zero, since this imposes a small efficiency penalty with no meaningful benefits
Declaring scalar (non-array) variables
If you have specified #DIM ALL or OPTION EXPLICIT, you have to declare all variables used in your programs. PowerBASIC provides a variation of the DIM statement for this job, because of the reduced level of syntax required for scalar variables. The following is a simplified syntax for DIM that just applies to scalar variables:
DIM var AS [GLOBAL | INSTANCE | LOCAL | STATIC | THREADED] type [PTR | POINTER] [, ...]
DIM var ' var must include a type-specifier
Here are some sample variable declarations:
DIM a AS LOCAL INTEGER
DIM b AS STATIC WORD
DIM c AS GLOBAL DOUBLE POINTER
DIM d AS STRINGZ * 255
DIM e AS THREADED STRING
LOCAL ASCIIZ, LOCAL fixed-length strings, and LOCAL UDTs are created on the stack frame of the Sub/Function/Method/Property in which they are declared. You must therefore use caution so that the combined local variable size does not exceed the allocated stack size. Unless you declare otherwise, PowerBASIC sets a default stack size of 1MB. If more stack space is required, you can allocate it with the #STACK metastament. There are no such limitations with GLOBAL, INSTANCE, THREADED, or STATIC variables.
When a DIM statement is used (without an explicit scope clause), to declare a variable in a procedure, and an identical variable has already been declared as GLOBAL, the variable in the procedure will be given GLOBAL scope. For example:
GLOBAL xyz AS LONG
DIM xyz AS LONG
' Here, xyz is a GLOBAL variable
To ensure that the variable scope is LOCAL to the Sub/Function/Method/Property, use a LOCAL statement rather than a DIM statement. Alternatively, add an explicit scope clause to the DIM statement. For example:
GLOBAL xyz AS LONG
DIM xyz AS LOCAL LONG
' Here, xyz is a LOCAL variable
Declaring pointer variables
A pointer must be declared before it can be used. You use the DIM statement to declare pointers, and describe the type of data to which they point. When a pointer is declared, it is automatically initialized to a value of zero. This is known as a null-pointer. You must remember to initialize it to a valid address, or you will get a General Protection Fault (GPF). The syntax for declaring pointer variables is similar to that of regular variables:
DIM var[(subscripts)] AS [GLOBAL | INSTANCE | LOCAL | STATIC | THREADED] type [PTR | POINTER] [, ...]
Here are some examples of pointer variable declarations:
DIM a AS BYTE PTR
DIM b AS INTEGER POINTER
DIM c AS STRING PTR * 25
DIM d AS MyType POINTER
DIM e(500) AS INTEGER PTR
Pointers themselves are stored as DWORD values.
The scope of a variable or array is set using the GLOBAL, INSTANCE, LOCAL, STATIC, or THREADED keywords.
When returning a pointer to a calling Sub, Function, Method, or Property, make sure the pointer target remains valid when the current routine terminates. For example, returning a pointer to a LOCAL variable is certain to trigger a GPF, since local storage is released when the routine ends. In this case, the pointers target should be STATIC, GLOBAL, or INSTANCE, or be valid within the scope of the calling code.
IAUTOMATION, IDISPATCH, IUNKNOWN, VARIANT and GUID variables have special uses with COM.