我用void类型参数写了两个方法:
procedure Method1(const MyVar; size: cardinal);
var
Arr: array of byte;
begin
SetLength(Arr, size);
{now copy the data from MyVar to Arr, but how?}
end;
procedure Method2(var MyVar; size: cardinal);
var
Arr: array of byte;
begin
SetLength(Arr, size);
{return the data from the array, but how?}
end;
在第一个中,我想将MyVar作为一个byte数组访问。在第二个中,我想将数据从本地数组Arr复制到MyVar。因此我使用了CopyMemory()函数,但它有些问题。
如果我在第二种方法中使用以下内容,只要调用Method2并将数组作为参数(Method2(指针(MyString)^,长度(MyString))或Method2(指针(MyArray)),就可以了,长度(MYARRAY)))。
CopyMemory(Pointer(MyVar), Pointer(Arr), size);
如果我用一个整数参数(Method2(MyInteger,SizeOf(MyInteger)))调用Method2,它就无法正常工作。在这种情况下,必须以这种方式调用CopyMemory():
CopyMemory(@MyVar, Pointer(Arr), size);
如何正确地从Method2返回数据,而不知道它是简单类型(或记录)还是数组? Method1中的情况类似,但在这里我必须使用
CopyMemory(Pointer(Arr), Pointer(MyVar), size);
如果是数组和
CopyMemory(Pointer(Arr), @MyVar, size);
如果是简单类型。
当我不知道MyVar参数是什么时,我该怎么办?
答案 0 :(得分:6)
在Delphi中没有这样的虚空类型。你所指的是untyped parameter。
无类型参数始终是实际的东西,而不是指向您应该使用的东西的指针。因此,将CopyMemory
与此类参数一起使用的正确方法是将@
运算符应用于此,如下所示:
CopyMemory(@MyVar, @Arr[0], size);
注意我也改变了传递第二个参数的方式。如果你不依赖于动态数组实际上是指向第一个元素的指针的事实,那就更好了。如果你需要一个指向第一个元素的指针,那就明确说出来,就像我在这里做的那样。
您的混淆来自于您使用参数进行的测试,就好像它是一个指针一样,测试似乎有效。不过,我怀疑该测试的有效性。当你说Pointer(MyString)^
时,你所拥有的是字符串的第一个字符。当你在函数内部说Pointer(MyVar)
时,你将该字符输入到指针中,这是一个无效的类型转换。如果你的程序似乎工作,那只是偶然的;你的代码错了。
我能给出的最好的建议是不要输入内容,除非你真的需要。当你这样做时,请确保你输入的东西真的有那种类型。在您的情况下,在将其作为无类型参数传递之前,您不需要输入任何内容。您可以像这样致电Method1
:
Method1(MyString[1], Length(MyString) * Sizeof(Char));
(我乘以SizeOf(Char)
,因为我不知道你是否有Delphi 2009.)
另外,请避免使用无类型参数。编译器可以帮助确保程序正确性的一个好处是强制类型安全,但是当你拿走类型时,编译器就无法帮助你了。
答案 1 :(得分:4)
您的问题是您将数据或指针传递给Method1 / 2。您应该始终传递数据。 可能你只是忘了动态数组是一个指针本身?你不应该在你的方法中传递A或指针(A)(这里的A是动态数组)。传递A [0]或指针(A)^。
procedure Method1(const MyVar; size: cardinal);
var
Arr: array of byte;
begin
SetLength(Arr, size);
CopyMemory(Pointer(Arr), @MyVar, Size);
end;
procedure Method2(var MyVar; size: cardinal);
var
Arr: array of byte;
begin
SetLength(Arr, size);
Arr[0] := 1;
Arr[1] := 2;
Arr[2] := 3;
Arr[3] := 4;
CopyMemory(@MyVar, Pointer(Arr), Size);
end;
procedure TForm1.FormCreate(Sender: TObject);
var
I: Integer;
A: array of Integer;
begin
I := $01020304;
Method1(I, 4); // we pass data itself, not the pointer to it.
Method2(I, 4);
SetLength(A, 2);
A[0] := 0;
A[1] := $01020304;
Method1(A[0], Length(A) * SizeOf(A[0])); // note, that we pass data, not pointer
Method2(A[0], Length(A) * SizeOf(A[0])); // A or Pointer(A) is a pointer to array's data
end;
如果A是动态数组:
如果A是静态数组:
注意,Method1 / 2中的Arr也是一个动态数组,这就是我们将它转换为指针的原因(CopyMemory询问指针,而不是数据)。如果我们想使用Move例程(询问数据),我们应该改写Pointer(A)^。