• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

Delphi - 从动态数组访问从非类型指针填充的数据

用户头像
it1352
帮助1

问题说明

我正在使用 Delphi 2009 ,而不是对我正在做的事情有很大的影响。我认为如果我仍然在 2007 ,我会遇到相同的。

I'm using Delphi 2009 not that it has a large affect on what I'm doing. I think I would run into the same if I was still on 2007.

我有一个scsi调用,将数据输出到指针(错误

I have a scsi call that outputs data to a pointer (wrong way of looking at it but i have trouble explaining that).

最初我使用移动填充一个字符串静态数组与回来的数据,但我想切换到调用时已知长度的动态数组。我已经尝试了几个不同结果的东西,一些获取数据,但有疯狂的访问冲突,其他人没有错误,但获得无效的数据。

Originally I used Move to populate a Static Array of Byte with the data that came back, but I'd like to switch to a Dynamic Array to which the length of is known at the time of the call. I've tried several things with varied results some get the data but have mad access violations others have no errors but get invalid data.

添加 setlength 到数组,然后使用 move ,首先要有一个空数组的设置长度,然后第二个不能像 OutputData [0] 那样访问数据,就像我做的时候是静态的,在调试器中移动后,所有内容都显示为无关紧要的价值或任何东西。

Adding setlength to the array and then using move, causes first to have an empty array of set length and then second not be able to access the data via like OutputData[0] like I did when it was static, in the debugger after the move everything shows as innaccesable value or whatever.

以下是我阅读了一篇文章,一个动态数组,并给出了一个地址的指针。它提到犯错误像孤儿数据。

Below is something I tried after reading an article that did the oposit took a dynamic array and gave a pointer that address. It mentioned making mistakes like orphaning data.

var
  Output: Pointer;
  OutputData: Array of byte;
  I: Integer;
begin
GetMem(Output, OutputLength.Value);
if SendPSPQuery(Char(DriveLetter[1]), cbxQuery.Items.IndexOf(cbxQuery.Text), Output, OutputLength.Value) = 0 then
  begin
    OutputData := @Output;
    for I := 0 to OutputLength.Value - 1 do
    begin
      edtString.Text := edtString.Text   Char(OutputData[I]);
    end;

有各种其他的东西,输出数据被使用,它被放在字符串和十六进制和东西

There is various otherstuff that th eoutput data is used for it gets put out in string and hex and things.

无论如何,如何将指针放入一个动态数组中,然后以数据的方式获取数据。

Anyway, how can I Take a Pointer put that data into a dynamic array and then grab that data the way you would address an array.

谢谢。

正确答案

#1

要使用动态数组,请使用 Move 程序,您需要传递第一个元素。例如:

To use a dynamic array with the Move procedure, you need to pass the first element of the array. For example:

var
  Source: Pointer;
  SourceSize: Integer;
  Destination: array of Byte;

SetLength(Destination, SourceSize);
Move(Source^, Destination[0], SourceSize);

请注意,第二个参数取消引用指针。这是因为 Move 采用您正在复制的,而不是指向该值的指针。你正在复制你的指针指向的东西,这就是你需要传递给 Move

Notice also that the second parameter dereferences the pointer. That's because Move takes the value that you're copying, not a pointer to the value. You're copying the stuff that your pointer points to, so that's what you need to pass to Move.

顺便提一句,如果 Destination 也是一个静态数组,那么这个相同的语法也是如此。而且对于Delphi 2009来说,这并不是特定的。对于Delphi 4来说,这是真的,这是在引入动态数组时。而移动已经有同样的奇怪的无类型参数语法永远。

Incidentally, that same syntax works if Destination is a static array, too. And you're right that this is not specific to Delphi 2009. It's true all the way back to Delphi 4, which is when dynamic arrays were introduced. And Move has had the same strange untyped parameter syntax forever.

不要使用 GetMem 然后键入转换,使编译器认为你有一个动态数组。 不是。动态数组具有普通字节缓冲区不具有的引用计数和长度字段,并且由于您无法控制编译器生成的所有代码以访问所假定的动态数组,所以您的程序将尝试访问数据结构不存在的数据。

Do not allocate your own memory with GetMem and then type-cast to make the compiler think that what you have is a dynamic array. It's not. Dynamic arrays have reference counts and length fields that an ordinary byte buffer won't have, and since you're not in control of all the code the compiler generates to access the supposed dynamic array, there's a danger that your program will try to access the data structure's nonexistent data.

您可以使PSP功能将其数据直接存储到动态数组中。以下是一些代码:

You could make the PSP function store its data directly into a dynamic array. Here's some code to do it:

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 超出范围时,编译器插入代码来释放动态数组,并且没有其他对数组的引用。这个代码需要一个动态数组,并将其传递为普通的缓冲区。这是有效的,并且是安全的,因为动态数组实际上是普通旧缓冲区的子类型。该函数将接受指向数组的第一个元素的指针,并将该指针视为指向一堆字节的指针,因为这正是它的原因。该函数不需要知道在程序用于动态数组记账的那些字节附近有附加的东西。

No need to free the memory afterward; the compiler inserts code to deallocate the dynamic array when Output goes out of scope and there are no other references to the array. This code takes a dynamic array and passes it as though it were an ordinary buffer. This works and is safe because a dynamic array is, in effect, a subtype of a plain old buffer. The function will accept a pointer to the first element of the array and treat the pointer as a pointer to a bunch of bytes because that's exactly what it is. The function doesn't need to know that there happens to be additional stuff adjacent to those bytes that the program uses for dynamic-array bookkeeping.

如果您的数据位于缓冲区,并且您希望将该缓冲区视为数组而不是将数据复制到单独的数据结构中,那么您有两个选项

If you have your data in a buffer and you want to treat that buffer as though it were the array, instead of copying the data into a separate data structure, then you have two options.

  1. 声明一个静态数组指针,然后键入您的缓冲区指针类型。这是经典技术,您可以在代码中使用它,特别是Delphi 4之前的代码。例如:

  1. Declare a static-array pointer, and then type-cast your buffer pointer to that type. This is the classic technique, and you can see it used in code all over the place, especially code that predates Delphi 4. For example:

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的长度。数组被声明与该大小部分作为一个线索,你不是真的应该声明该类型的变量。只能通过指针使用它。另一方面,如果您知道数据的最大大小是合适的,则可以使用该大小来声明数组类型,然后可以保持范围检查。 (如果您通常禁用范围检查,您只是要求麻烦。)

The $R directives are to make sure range checking is turned off for that code since the array type is declared to have a length of 1. The array is declared with that size in part to serve as a clue that you're not really supposed to declare a variable of that type. Only use it through a pointer. On the other hand, if you know what a suitable maximum size of the data will be, you can use that size to declare the array type instead, and then you can keep range checking turned on. (If you normally keep range checking disabled, you're just asking for trouble.)

将缓冲区声明为 PByte 而不是指针,然后使用Delphi的新(截至Delphi 2009)支持将任意指针类型视为数组指针。在以前的版本中,只有 PChar PAnsiChar PWideChar 支持这种语法。例如:

Declare your buffer as PByte instead of Pointer and then use Delphi's new (as of Delphi 2009) support for treating arbitrary pointer types as array pointers. In previous versions, only PChar, PAnsiChar, and PWideChar supported this syntax. For example:

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} 新的扩展语法。

The $POINTERMATH compiler directive is not required to enable this feature for PByte because that type is declared while that directive is in effect. If you want to do C-like pointer operations with other pointer types, then place {$POINTERMATH ON} before the code that makes use of the new extended syntax.






一次需要建立一个字符的字符串。这在两个方面是浪费的。首先,你正在构建很多字符串,每个字符串只比前一个字节大两个字节。第二,因为您将字符串结果存储在编辑控件中,您强制该控件的操作系统实现也会分配一堆新字符串。将您的数据放入一个字符串,然后将其全部附加到编辑控件中:


As a final note, you don't need to build up your strings one character at a time. It's wasteful in two ways. First, you're constructing lots of strings, each one just two bytes larger than the previous one. Second since you're storing the string result in an edit control, you're forcing the OS implementation of that control to allocate a bunch of new strings, too. Put your data into one string, and then append it all at once to your edit control:

var
  OutputString: AnsiString;

SetString(OutputString, PAnsiChar(Buffer), OutputLength.Value);
edtString.Text := edtString.Text   OutputString;

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /reply/detail/tanhcfkbak
系列文章
更多 icon
同类精品
更多 icon
继续加载