Open Arrays

From RAD Studio
Jump to: navigation, search

Go Up to Support for Delphi Data Types and Language Concepts


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)
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.

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) ;
Note: In cases similar to the above example, but where the Delphi 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

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)) ;
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 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>.