小弟对Delphi不熟悉,但是现在有一个用Delphi写的DLL,现在需要用C来调用这个DLL。在此DLL中有一个export函数的声明是这样的:
type // Type of plugin's functions
TFT0Command = function (const Header : array of byte;
const rwData : byte;
var DATA : array of byte;
wasRW : PWord) : LongInt;
stdcall;我用C语言来调用这函数的时候,函数中获得Header的长度不正确。
我想知道,在Delphi中是如何来确定数组的长度。
不要告诉我用SizeOf(array),Low(array),High(array)这些函数,我需要知道这些函数实现的原理。例如,在C语言中,如果要将一个数组作为参数来传递到一个函数中,需要同时将数组的长度也送到函数中去。但是在Delphi中并没有将数组的长度送过去,在函数中它是怎么获得数组的长度呢?
type // Type of plugin's functions
TFT0Command = function (const Header : array of byte;
const rwData : byte;
var DATA : array of byte;
wasRW : PWord) : LongInt;
stdcall;我用C语言来调用这函数的时候,函数中获得Header的长度不正确。
我想知道,在Delphi中是如何来确定数组的长度。
不要告诉我用SizeOf(array),Low(array),High(array)这些函数,我需要知道这些函数实现的原理。例如,在C语言中,如果要将一个数组作为参数来传递到一个函数中,需要同时将数组的长度也送到函数中去。但是在Delphi中并没有将数组的长度送过去,在函数中它是怎么获得数组的长度呢?
这段说明中并没有解释SizeOf(array)是如何获得数组的长度的呀!
我觉得,在动态数组或者开放数组中,应该有一部分内存用来保存数组的长度才行。
这种说法是不对的!这并不名Delphi中的String,而在别的语言当中string也是没有这种功能的!
我想一个数组应该有一个结束的标志
p:pinteger;
begin
setlength(a,100);
p:= pinteger(a);
dec(p);
edit1.text:=IntToStr(p^);end;
如果我没有理解错的话,楼上兄弟的意思是,在这个数组的第一个元素的储存空间之前有4byte的内存空间,这4byte的内存空间中保存的就是数组长度。对吗?
如果是这样,我还有一个问题:一个function的参数是开放数组,并没有setlength(a,100);这样的一个语句,那么这个开放数组的长度又是如何设定的呢?能在调用这个函数的程序中设定这个值吗?
这段说明中并没有解释SizeOf(array)是如何获得数组的长度的呀!
我觉得,在动态数组或者开放数组中,应该有一部分内存用来保存数组的长度才行。是有的 不然内存怎么能管理好呢 这就是所谓的 memory cookie.
length(array) 而不是sizeof(array)吧?后者编译器在编译时候,就判断变量类型,将结果,也就是立即数4编译进指令。前者是调用了SYSTEM。PAS单元的
procedure _DynArrayLength;
asm
{ FUNCTION _DynArrayLength(const a: array of ...): Longint; }
{ ->EAX Pointer to array or nil }
{ <-EAX High bound of array + 1 or 0 } TEST EAX,EAX
JZ @@skip
MOV EAX,[EAX-4]
@@skip:
end;
我现在最想知道的一件是就是:
Delphi中,如果一个函数的参数是开放数组,编译器最终生成的代码中是如何确定这个开放数组的长度的?
因为我现在是用C来调用一个用Delphi写的DLL,这个Dll中有一个export函数的参数是开放数组,我如果直接将数组的首地址从C中传到Delphi函数中的话,Delphi函数不能正确的判断出数组的长度。
所以我现在就想知道,在Delphi中开放数组的长度是如何确定的。
我列出来的代码也不是PASCAL,呵呵。。几句很简单的汇编而已。procedure _DynArrayLength;
asm
TEST EAX,EAX //EAX是传入参数
JZ @@skip
MOV EAX,[EAX-4] //这儿EAX是RETURN值。
end;它翻译成C语言差不多就是。。
int _DynArrayLength(void * p)
{
if(p)
{
int* r=(int*)p; //为了容易看,加了一个中间变量。
return *(r-1); //一个整型四字节,r-1意味着指针指向之前四个字节。
}
else
return 0;}
zjqyb(风清扬)的回答我也大概看明白了。
但是他的回答并没有完全消除我的疑惑。
他举了一个动态数组的例子,在他的例子中,通过setlength(a,100);对这个动态数组进行了内存分配的任务。
我现在想知道的是作为函数参数的开放数组。在使用开放数组的时候并没有setlength这样一个明显的内存分配的动作,而且如果在声明函数的参数时加上了var或者const关键字,函数和调用函数的程序对这个数组的操作是指向同一块内存区域的,在这种情况下,在函数中根本就没有再次为这个数组进行分配内存的动作。在这种情况下,Delphi是如何确定数组大小的呢?
为动态数组重分配内存也是用它。
确定数组大小,就靠那开头四字节唯一确定,这是不用怀疑的。
如果参数是VAR,则调用方可先SETLENGTH分配内存,被调用方也可再SETLENGTH。。
尽管都是传的指针,这是调用上一些约定,
在C++语言编译器本身没有作这样的区分。。所以容易迷糊。
-----------------------------------------------------------
还有一点,DELPHI中动态数组是引用计数维护呵呵不过好象你这个DLL调用
可以回避这些。。
在使用C来调用Delphi写的以开放数组为参数的Dll中的导出函数的时候,需要在数组之后再加一个整形的参数,将数组中最大的索引送过去。而这种方式是典型的C/C++中函数参数为数组的调用方式。例如,我这个Delphi的函数
type // Type of plugin's functions
TFT0Command = function (const Header : array of byte;
const rwData : byte;
var DATA : array of byte;
wasRW : PWord) : LongInt;
stdcall;
如果用C来调用的话,要这么写:
typedef LONG (__stdcall *TFT0Command)(const BYTE[],
INT,
const BYTE,
BYTE[],
INT,
PWORD);我猜想在Delphi中,如果定义函数的时候加上了stdcall关键字,会使编译器生成的代码与C/C++生成代码保持结构上的一致。