要在Move
过程中使用动态数组,您需要传递数组的第一个元素。例如:
var
Source: Pointer;
SourceSize: Integer;
Destination: array of Byte;
SetLength(Destination, SourceSize);
Move(Source^, Destination[0], SourceSize);
另请注意,第二个参数取消引用指针。那是因为Move
获取您正在复制的值,而不是指向该值的指针。你正在复制你的指针指向的东西,所以这就是你需要传递给Move
.
顺便说一句,如果Destination
是静态数组,同样的语法也适用。你是对的,这并不是 Delphi 2009 特有的。一直到 Delphi 4 都是如此,那是引入动态数组的时候。并且永远Move
具有相同的奇怪的无类型参数语法。
不要分配您自己的内存GetMem
然后进行类型转换以使编译器认为您拥有的是动态数组。不是。动态数组具有普通字节缓冲区没有的引用计数和长度字段,并且由于您无法控制编译器为访问假定的动态数组而生成的所有代码,因此您的程序可能会尝试访问数据结构中不存在的数据。
您可以让 PSP 函数将其数据直接存储到动态数组中。这是一些代码:
var
Output: array of Byte;
SetLength(Output, OutputLength.Value);
if SendPSPQuery(Char(DriveLetter[1]),
cbxQuery.Items.IndexOf(cbxQuery.Text),
@Output[0],
OutputLength.Value) = 0
then
之后无需释放内存;当Output
超出范围并且没有其他对数组的引用时,编译器会插入代码以释放动态数组。此代码接受一个动态数组并将其作为普通缓冲区传递。这有效且安全,因为动态数组实际上是普通旧缓冲区的子类型。该函数将接受指向数组第一个元素的指针,并将指针视为指向一堆字节的指针,因为这正是它的本质。该函数不需要知道与程序用于动态数组簿记的那些字节相邻的其他内容。
如果您将数据放在缓冲区中,并且希望将该缓冲区视为数组,而不是将数据复制到单独的数据结构中,那么您有两种选择。
声明一个静态数组指针,然后将缓冲区指针类型转换为该类型。这是经典的技术,你可以看到它在很多地方的代码中使用,尤其是在 Delphi 4 之前的代码。例如:
type
PByteArray = ^TByteArray;
TByteArray = array[0..0] of Byte;
var
ByteArray: PByteArray;
ByteArray := PByteArray(Output);
for i := 0 to Pred(OutputLength.Value) do begin
{$R-}
edtString.Text := edtString.Text + Chr(ByteArray[i]);
{$R+}
end;
这些$R
指令是为了确保该代码的范围检查被关闭,因为数组类型被声明为长度为 1。该数组被声明为具有该大小,部分是为了作为您不应该真正声明的线索该类型的变量。只能通过指针使用它。另一方面,如果您知道合适的最大数据大小,您可以使用该大小来声明数组类型,然后您可以保持打开范围检查。(如果您通常禁用范围检查,那么您只是在自找麻烦。)
将缓冲区声明为PByte
,Pointer
然后使用 Delphi 的新(自 Delphi 2009 起)支持将任意指针类型视为数组指针。在以前的版本中,只有PChar
、PAnsiChar
和PWideChar
支持这种语法。例如:
var
Output: PByte;
for i := 0 to Pred(OutputLength.Value) do begin
edtString.Text := edtString.Text + Chr(Output[i]);
end;
$POINTERMATH
不需要编译器指令来启用此功能,因为PByte
该类型是在该指令生效时声明的。如果您想对其他指针类型执行类似 C 的指针操作,请放在{$POINTERMATH ON}
使用新扩展语法的代码之前。
最后一点,您不需要一次构建一个字符的字符串。浪费在两个方面。首先,您正在构建大量字符串,每个字符串仅比前一个字符串大两个字节。其次,由于您将字符串结果存储在编辑控件中,因此您也强制该控件的操作系统实现分配一堆新字符串。将您的数据放入一个字符串中,然后一次将其全部附加到您的编辑控件中:
var
OutputString: AnsiString;
SetString(OutputString, PAnsiChar(Buffer), OutputLength.Value);
edtString.Text := edtString.Text + OutputString;