Open Arrays
Go Up to Support for Delphi Data Types and Language Concepts
Contents
Support for Open Arrays
Delphi 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 Delphi 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)
_Size
suffix in the past, but now it has the _High
suffix instead, which is equivalent to _Size minus 1
.For example, the Mean function in math.hpp has the following declarations, in Delphi and in C++:
Delphi declaration:
function Mean(Data: array of Double): Double;
C++ declaration:
double __fastcall Mean(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
double x = Mean(d, 2) ;
// better: use sizeof to ensure that the correct value is passed
double y = Mean(d, ( sizeof (d) / sizeof (d[0])) - 1) ;
// use macro in sysopen.h
double z = Mean(d, ARRAYSIZE(d) - 1) ;
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
Delphi 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
Delphi 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 Delphi 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)) ;
C++ functions that take open array arguments
When writing a C++ function that will be passed an open array from Delphi, 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 Delphi, 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.
Delphi functions that return arrays
Delphi allows functions to return arrays, but C++ does not. To reconcile this difference, Delphi methods that return arrays (such as T[1..n]
) are prototyped as returning an instance of StaticArray<T, n>
.