delphi与变长参数——开放数组(1)

 

       与C/C++不同,Delphi中是通过可变类型(TVarRec)的开放数组来指定变长参数的。其实这里已经不能称“变长参数”了,因为实际上只传递了一个参数,只是该参数是由多个基础类型数据构成的一个开放数组。Delphi使用开放数组来容纳不定数目的参数,使用可变类型(TVarRec)表示各种类型数据,因此二者的结合可以达到C/C++中变长参数的功能。

       TVarRec是一个记录类型,该记录的VType字段标志记录值的类型,如整数、布尔、字符、实数、字符串、指针、类、类引用、接口、变体等。【注1】

//这是定义在 System 单元关于数据类型的一个结构:
TVarRec = record
  case Byte of
    vtInteger:    (VInteger: Integer; VType: Byte);
    vtBoolean:    (VBoolean: Boolean);
    vtChar:       (VChar: Char);
    vtExtended:   (VExtended: PExtended);
    vtString:     (VString: PShortString);
    vtPointer:    (VPointer: Pointer);
    vtPChar:      (VPChar: PChar);
    vtObject:     (VObject: TObject);
    vtClass:      (VClass: TClass);
    vtWideChar:   (VWideChar: WideChar);
    vtPWideChar:  (VPWideChar: PWideChar);
    vtAnsiString: (VAnsiString: Pointer);
    vtCurrency:   (VCurrency: PCurrency);
    vtVariant:    (VVariant: PVariant);
    vtInterface:  (VInterface: Pointer);
    vtWideString: (VWideString: Pointer);
    vtInt64:      (VInt64: PInt64);
end;

      

       那么开放数组又是什么?关于开放数组,官方文档给出的解释是:

(1)Object Pascal has an “open array” construct that permits an array of unspecified size to be passed to a function.

面向对象Pascal有一个开放数组的概念允许向一个方法传递未指定大小的数组。

(2)an Object Pascal function that has an open array parameter can be called by explicitly passing both the pointer to the first element of an array and the value of the last index (number of array elements, minus one).

一个面向对象的含有开放数组参数的Pascal函数能通过传递数组的第一个元素的地址和最后一个元素的索引(即数组大小减1)来调用。

 

//官方例子
//Object Pascal声明
function  Mean(Data:  array of  Double): Extended;
//Pascal调用
Result := Mean([3.1, 4.4, 5.6]);
//官方例子
//C++声明
Extended  __fastcall  Mean( const double  * Data,  const int  Data_Size);
//C++调用
double  d[] = { 3.1, 4.4, 5.6 } ; 
return  Mean(d, 2) ;

 

       看了官方文档还是一头雾水,根本就没解释什么是开放数组。好像开放数组与动态数组是一样的嘛!在Delphi中,数组类型有静态数组(array[0..1024] of integer)、动态数组(array of integer)两类。关于动态数组,官方文档给出的解释是:

(3)Dynamic arrays do not have a fixed size or length. Instead, memory for a dynamic array is reallocated when you assign a value to the array or pass it to the SetLength procedure.

动态数组没有固定大小或长度。你可以通过给动态数组赋值或使用SetLength方法给动态数组重新分配内存。

//定义动态数组变量
var MyFlexibleArray: array of Real;
//分配内存
SetLength(MyFlexibleArray, 20);

       动态数组变量是一个隐式指针,它是由引用计数技术进行管理的。其使用方法这里不多说,这里看下官方给出的Note。

(4)Note: In some function and procedure declarations, array parameters are represented as array of baseType, without any index types specified.

注意:在一些函数或过程的声明中,数组参数被描述成没有索引类型标识符的“array of baseType”形式。

//官方例子
function CheckStrings(A: array of string): Boolean;

(5)This indicates that the function operates on all arrays of the specified base type, regardless of their size, how they are indexed, or whether they are allocated statically or dynamically.

这表明这个函数可以操作(即接受实参)所有指定的baseType类型的数组,无论该数组的大小是多少、该数组是如何索引的和该数组是静态分配还是动态分配。

       其实这里说的就是开放数组参数,这该死的官方文档,它就是不指明一下。

       网上文章在介绍动态数组时都是用“array of Type”进行定义;而在讨论开放数组时又说“array of Type”定义的是开放数组,通过“Type TArr=array of Type;var a:TArr;”定义的才是动态数组。经过大量搜索阅读,我的理解是:在函数声明中使用“array of Type”定义形参的是开放数组;而在其他位置使用“array of Type”定义数组变量的是动态数组。

       其实很多时候,只有在讨论函数的数组参数时才有开放数组一说,很多时候也是以开放数组参数进行阐述的。这也与官方文档给出的解释一致:开放数组是在给方法传递数组参数时的一个概念。静态数组和动态数组都可以传递给开放数组参数,Delphi隐式(自动地)传递它们的长度。【注2】

       开放数组参数实际上是一个包含指向数组第一个元素地址的指针和调整后以0开始的数组元素的最大索引值(即数组长度减1)的结合物。针对前面声明Mean函数,它实际上的参数列表如下所示:【注3】

function Mean(PData:Pointer; High: Integer): Extended;

这一点与前面官方文档给出的第(2)条解释一致,只是Delphi使用开放数组参数将这个细节给隐藏了,我们只需将静态或动态数组的首地址(即数组变量名)传递给函数,对于静态数组,编译器直接传递数组大小(减1),对于动态数组,编译器自动生成代码以便在运行时获取动态数组的High值。

 

 

       下接delphi与变长参数——开放数组(2)。

 

 

 

 

注1:更多有关TVarRec的内容请参考http://docwiki.embarcadero.com/VCL/en/System.TVarRec

注2:Both static and dynamic arrays may be passed to subroutines as parameters. If the array parameter definition has no range (ie, a dynamic array type), then you must, paradoxically pass a static array as a parameter. Such an array is referred to as an Open array. Delphi passes the length as a hidden parameter to the subroutine.(详情请参考http://www.delphibasics.co.uk/RTL.asp?Name=Array )

注3:An open array parameter is actually acombination of two parameters, a pointer, which contains the address of the start of the array, and an integer, which contains the High value, adjusted for a zero base.(详情请参考http://rvelthuis.de/articles/articles-openarr.html的Internals一节)

 

 

 

 

 

你可能感兴趣的:(function,Integer,Arrays,Delphi,pascal)