Open Arrays
Go Up to Support for Object Pascal Data Types and Language Concepts
Contents
Support for Open Arrays
Object Pascal has an "open array" construct that permits an array of unspecified size to be passed to a function. While there is no direct support in C++ for this type, an Object Pascal function that has an open array parameter can be called by explicitly passing two parameters:
- A pointer to the first element of the array
- A count, which is the value of the last index (that is, the size/number of array elements, minus one)
- Note: The count parameter had the
_Size
suffix in the past, but now it has the_High
suffix instead, which is equivalent to_Size minus 1
.
- Note: The count parameter had the
For example, the Mean function in math.hpp has the following declarations, in Object Pascal and in C++:
Delphi declaration:
function Mean(Data: array of Double): Double;
C++ declaration:
float __fastcall Mean( float double * Data, const int Data_High);
The following code illustrates calling the Mean function from C++:
double d[] = { 3.1, 4.4, 5.6 };
// explicitly specifying last index
long double x = Mean(d, 2) ;
// better: use sizeof to ensure that the correct value is passed
long double y = Mean(d, ( sizeof (d) / sizeof (d[0])) - 1) ;
// use macro in sysopen.h
long double z = Mean(d, ARRAYSIZE(d) - 1) ;
Note: In cases similar to the above example, but where the Object Pascal function takes a var parameter, the C++ function declaration parameters will not be
const
.
Calculating the number of elements
When using sizeof(), the ARRAYSIZE macro, or the EXISTINGARRAY macro to calculate the number of elements in an array, be careful not to use a pointer to the array. Instead, pass the name of the array itself.
double d[] = { 3.1, 4.4, 5.6 } ;
int n = ARRAYSIZE(d); // sizeof (d)/ sizeof (d[0]) => 24/8 => 3
double *pd = d;
int m = ARRAYSIZE(pd); // sizeof (pd)/ sizeof (pd[0]) => 4/8 => 0 => Error !
Taking the size of an array (with “sizeof”) is not the same as taking the size of a pointer (with “sizeof”). For example, given the following declarations,
double d[3];
double *p = d;
taking the size of the array as shown here
sizeof (d) / sizeof d[0]
does not evaluate the same way as taking the size of the pointer:
sizeof (p) / sizeof (p[0])
This example and those following use the ARRAYSIZE macro instead of the sizeof() operator. For more information about the ARRAYSIZE macro, see the online Help.
Temporaries
Object Pascal provides support for passing unnamed temporary open arrays to functions. There is no syntax for doing this in C++. However, since variable definitions can be intermingled with other statements, one approach is to simply provide the variable with a name.
Delphi:
Result := Mean([3.1, 4.4, 5.6]);
C++, using a named “temporary”:
double d[] = { 3.1, 4.4, 5.6 } ;
return Mean(d, ARRAYSIZE(d) - 1) ;
To restrict the scope of the named “temporary” to avoid clashing with other local variables, open a new scope in place:
long double x;
{
double d[] = { 4.4, 333.1, 0.0 } ;
x = Mean(d, ARRAYSIZE(d) - 1) ;
}
For another solution, see OPENARRAY macro.
array of const
Object Pascal supports a language construct called an array of const. This argument type is the same as taking an open array of TVarRec by value.
The following is an Object Pascal code segment declared to accept an array of const:
function Format( const Format: string ; Args: array of const ): string ;
In C++, the prototype is:
UnicodeString __fastcall Format( const UnicodeString Format ,
TVarRec const *Args, const int Args_Size) ;
The function is called just like any other function that takes an open array:
void show_error ( int error_code, UnicodeString const &error_msg)
{
TVarRec v[] = { error_code, error_msg } ;
ShowMessage(Format("%d: %s", v, ARRAYSIZE(v) - 1)) ;
}
OPENARRAY macro
The OPENARRAY macro defined in sysopen.h can be used as an alternative to using a named variable for passing a temporary open array to a function that takes an open array by value.
The use of the macro looks like:
OPENARRAY(T, (value1, value2, value3)) // up to 19 values
where T is the type of open array to construct, and the value parameters will be used to fill the array. The parentheses around the value arguments are required. For example:
void show_error(int error_code, UnicodeString const &error_msg)
{
ShowMessage(Format("%d: %s", OPENARRAY(TVarRec, (error_code, error_msg))));
}
Up to 19 values can be passed when using the OPENARRAY macro. If a larger array is needed, an explicit variable must be defined. Additionally, using the OPENARRAY macro incurs an additional (but small) run-time cost, due both to the cost of allocating the underlying array and to an additional copy of each value.
Code Samples
EXISTINGARRAY macro
The EXISTINGARRAY macro defined in sysopen.h can be used to pass an existing array where an open array is expected.
The use of the macro looks like:
long double Mean( const double *Data, const int Data_Size) ;
double d[] = { 3.1, 3.14159, 2.17128 } ;
Mean(EXISTINGARRAY (d)) ;
Note: The section Calculating the number of elements also applies to the EXISTINGARRAY macro.
C++ functions that take open array arguments
When writing a C++ function that will be passed an open array from Object Pascal, it is important to explicitly maintain “pass by value” semantics. In particular, if the declaration for the function corresponds to “pass by value”, be sure to explicitly copy any elements before modifying them. In Object Pascal, an open array is a built-in type and can be passed by value. In C++, the open array type is implemented using a pointer, which will modify the original array unless you make a local copy of it.
Object Pascal functions that return arrays
Object Pascal allows functions to return arrays, but C++ does not. To reconcile this difference, Object Pascal methods that return arrays (such as T[1..n]
) are prototyped as returning an instance of StaticArray<T, n>
.