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

2023-12-05

我在用着德尔福2009并不是说它对我正在做的事情有很大的影响。我想如果我还在的话我也会遇到同样的情况2007.

我有一个 scsi 调用,它将数据输出到指针(查看它的方式是错误的,但我很难解释这一点)。

本来我用的是Move填充一个静态字节数组与返回的数据,但我想切换到动态数组的长度在调用时已知。我尝试了几种结果各异的方法,有些得到了数据,但出现了严重的访问冲突,有些则没有错误,但得到了无效数据。

Adding 设定长度到数组,然后使用move,导致第一个有一个设定长度的空数组,然后第二个无法通过类似的方式访问数据输出数据[0]就像我在静态时所做的那样,在移动后的调试器中,所有内容都显示为不可访问的值或其他值。

下面是我在阅读一篇文章后尝试的方法,该文章做了相反的操作,采用动态数组并给出了该地址的指针。它提到会犯诸如孤立数据之类的错误。

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;

输出数据还有各种其他用途,因为它以字符串和十六进制等形式输出。

无论如何,我如何使用指针将该数据放入动态数组中,然后以寻址数组的方式获取该数据。

Thanks.


使用动态数组the Move程序,你需要通过第一个元素数组的。例如:

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

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

另请注意,第二个参数取消引用指针。那是因为Move采取value您正在复制的内容,而不是指向该值的指针。您正在复制指针指向的内容,因此这就是您需要传递给的内容Move.

顺便说一句,如果Destination也是一个静态数组。您说得对,这并不是 Delphi 2009 所特有的。一直到 Delphi 4 都是如此,当时引入了动态数组。和Move也有过同样的奇怪无类型参数永远的语法。


不要分配自己的内存GetMem然后进行类型转换,使编译器认为您拥有的是动态数组。It's not。动态数组具有普通字节缓冲区所没有的引用计数和长度字段,并且由于您无法控制编译器生成的用于访问假定的动态数组的所有代码,因此您的程序存在尝试访问的危险数据结构中不存在的数据。

您可以使 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超出范围并且没有对该数组的其他引用。此代码采用动态数组并将其传递,就像它是普通缓冲区一样。这有效并且安全,因为动态数组实际上是普通旧缓冲区的子类型。该函数将接受指向数组第一个元素的指针,并将该指针视为指向一堆字节的指针,因为这正是它的本质。该函数不需要知道程序用于动态数组簿记的那些字节附近恰好有其他内容。


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

  1. 声明一个静态数组pointer,然后将缓冲区指针类型转换为该类型。这是经典技术,您可以在各处的代码中看到它的使用,尤其是 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;
    

    The $R指令的目的是确保关闭该代码的范围检查,因为数组类型被声明为长度为 1。使用该大小声明数组的部分原因是作为一个线索,表明您实际上不应该声明一个该类型的变量。仅通过指针使用它。另一方面,如果您知道数据的合适最大大小是多少,则可以使用该大小来声明数组类型,然后可以保持范围检查处于打开状态。 (如果您通常禁用范围检查,那么您只是自找麻烦。)

  2. 将您的缓冲区声明为PByte代替Pointer然后使用Delphi的新功能(截至Delphi 2009)支持将任意指针类型视为数组指针。在以前的版本中,仅PChar, PAnsiChar, and PWideChar支持这种语法。例如:

    var
      Output: PByte;
    
    for i := 0 to Pred(OutputLength.Value) do begin
      edtString.Text := edtString.Text + Chr(Output[i]);
    end;
    

    The $POINTERMATH不需要编译器指令来启用此功能PByte因为那个类型是declared在该指令生效期间。如果你想进行类似 C 的指针操作other指针类型,然后放置{$POINTERMATH ON}在使用新扩展语法的代码之前。


最后一点,您不需要一次构建一个字符的字符串。这在两个方面都是浪费。首先,您正在构建大量字符串,每个字符串仅比前一个大两个字节。其次,由于您将字符串结果存储在编辑控件中,因此您也强制该控件的操作系统实现分配一堆新字符串。将您的数据放入one字符串,然后将其一次性全部附加到您的编辑控件中:

var
  OutputString: AnsiString;

SetString(OutputString, PAnsiChar(Buffer), OutputLength.Value);
edtString.Text := edtString.Text + OutputString;
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Delphi - 从由非类型化指针填充的动态数组访问数据 的相关文章

  • 无法将新地址分配给函数中的指针? [复制]

    这个问题在这里已经有答案了 不久前 我有一个编程作业 偶然发现了这个小问题 当我给一个函数一个指针作为参数时 我无法更改它指向的地址 我通过返回我想要指针指向的新地址解决了这个问题 但我仍然想知道为什么不可能操作指针参数 因为所有内存分配函
  • 当用户到达 UITableView 的最后一行时,如何动态添加行?

    我有一个UITableview当前显示 10 行 固定为静态 现在我想在其中添加一个功能 当用户到达最后一行时 我想向表中添加更多 10 行UITableView 我的意思是目前我在应用程序中显示固定的 10 行 但现在我想在用户到达上一个
  • 以编程方式重新启动 Delphi 应用程序

    应该不可能运行我的应用程序的多个实例 因此项目源码包含 CreateMutex nil False PChar ID if GetLastError ERROR ALREADY EXISTS then Halt 现在我想以编程方式重新启动我
  • TOpenDialog/NSOpenPanel 无法在沙盒 Delphi 应用程序中工作

    Firemonkey 应用程序中的 TOpenDialog 似乎存在问题 该应用程序已针对 Mac Appstore 进行沙箱处理 我使用XE3 但它也存在于XE2中 我其实在这里找到了一份QC报告 但仍然没有解决 http qc emba
  • 为什么我不能对普通变量进行多态?

    我是一名Java程序员 最近开始学习C 我对某事感到困惑 据我了解 在 C 中 要实现多态行为 您必须使用指针或引用 例如 考虑一个类Shape与实施的方法getArea 它有几个子类 每个子类都以不同的方式重写 getArea 然后考虑以
  • 调整巨大数组的大小

    我正在我的应用程序中处理巨大的数组 需要调整它们的大小 假设您有一个 2Gb 的阵列 并且想要将其大小调整为 3Gb 有没有办法在暂时不需要 5Gb 的情况下调整它的大小 例如 给定一个 1Gb 堆 使用 Xmx1G flag public
  • 删除指向对象的 C++ 指针

    我认为删除命令会释放我分配的内存 有人可以解释为什么删除后我似乎仍然有内存在使用吗 class Test public int time int main Test e e new Test e gt time 1 cout lt lt e
  • 将 UUID 存储为 base64 字符串

    我一直在尝试使用 UUID 作为数据库键 我希望占用尽可能少的字节数 同时仍然保持 UUID 表示形式的可读性 我认为我已经使用 base64 将其减少到 22 个字节 并删除了一些尾随的 这些 对于我的目的来说似乎没有必要存储 这种方法有
  • .push() 将多个对象放入 JavaScript 数组中返回“未定义”

    当我将项目添加到beats数组然后console log用户时 我得到了数组中正确的项目数 但是当我检查 length 时 我总是得到 1 尝试调用索引总是会给我 未定义 如下所示 Tom beats 1 我想我错过了一些明显的东西 但这让
  • 为什么未初始化的指针会导致内存访问冲突接近 0?

    据说often 但并非总是如此 当你在接近于零的内存位置 比如 89 美元 获得 AV 时 你就有了一个未初始化的指针 但我也在 Delphi 书籍中看到了这一点 嗯 或者它们都是由同一作者写的 Update 引自 Bob Swart 等人
  • 当responseText包含有效的Xml时,IXMLHttpRequest.responseXml为空,没有解析错误

    我正在从中获取一些 XML政府网站 http www bankofcanada ca stats assets rates rss noon en all xml http www bankofcanada ca stats assets
  • 传递给函数时多维数组的指针类型是什么? [复制]

    这个问题在这里已经有答案了 我在大学课堂上学习了 C 语言和指针 除了多维数组和指针之间的相似性之外 我认为我已经很好地掌握了这个概念 我认为由于所有数组 甚至多维 都存储在连续内存中 因此您可以安全地将其转换为int 假设给定的数组是in
  • 在 NumPy 中获取 ndarray 的索引和值

    我有一个 ndarrayA任意维数N 我想创建一个数组B元组 数组或列表 其中第一个N每个元组中的元素是索引 最后一个元素是该索引的值A 例如 A array 1 2 3 4 5 6 Then B 0 0 1 0 1 2 0 2 3 1 0
  • 从 pygame 获取 numpy 数组

    我想通过 python 访问我的网络摄像头 不幸的是 由于网络摄像头的原因 openCV 无法工作 Pygame camera 使用以下代码就像魅力一样 from pygame import camera display camera in
  • 每次 TDbGrid 的选定位置更改时都会触发什么事件?

    我的项目中有一个 TDbGrid 每次更改所选行时我都试图触发一个事件 行中的任何更改都已经更新了链接到同一数据源的所有数据感知控件 但还需要进行其他更改 我需要一个事件处理程序 我认为 OnColEnter 会起作用 根据帮助文件 它在以
  • C# 和匿名对象数组

    这样的表达是什么意思呢 obj DataSource new new Text Silverlight Count 10 Link Tags Silverlight new Text IIS 7 Count 11 Link http iis
  • $0 和 $1 在 Swift 闭包中意味着什么?

    let sortedNumbers numbers sort 0 gt 1 print sortedNumbers 谁能解释一下什么 0 and 1在斯威夫特中意味着什么 另一个样本 array forEach actions append
  • reinterpret_cast 为 void* 是否合法

    我在看https en cppreference com w cpp language reinterpret cast https en cppreference com w cpp language reinterpret cast我注
  • 如何从 appsettings.json 文件中的对象数组读取值

    我的 appsettings json 文件 StudentBirthdays Anne 01 11 2000 Peter 29 07 2001 Jane 15 10 2001 John Not Mentioned 我有一个单独的配置类 p
  • Mac 上的 Delphi - 可能吗? [关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我负责一个 Delphi Win32 项目管理应用程序 我刚刚完成了向 Delphi 2009 的迁移

随机推荐

  • 有什么充分的理由使用 FormCollection 而不是 ViewModel 吗?

    我继承了用 ASP Net MVC 4 编写的代码库 每个 post 方法都需要一个FormCollection 除了必须通过带引号的字符串访问值的烦恼之外 它还会导致一些缺点 例如无法使用诸如ModelState IsValid or A
  • 如何在c中确定linux中的目录或文件

    我只想打印文件名而不打印目录名称 所以我实现了这个功能 void list file char directory DIR d struct dirent dir d opendir directory if d while dir rea
  • clientHeight/clientWidth 在不同浏览器上返回不同的值

    特性document body clientHeight and document body clientWidth在 IE7 IE8 和 Firefox 上返回不同的值 IE 8 document body clientHeight 70
  • Elasticsearch 结合多个存储桶和聚合

    假设我们正在查看相当简单的数据 索引中的每个文档都具有以下结构 Time 2018 01 01T19 35 00 0000000Z Country Germany Addr security web com FailureCount 5 S
  • 在 R 中生成一个具有 m 列和 n 行的随机矩阵,其中行总和为 1

    我想生成一个 nxm 矩阵 假设它是 100x3 我希望每一行的总和为 1 因此两个 0 和一个 1 sample c 0 0 1 3 会给我 1 行 但是有没有一种非常快速的方法可以在没有 rbind 的情况下生成整个矩阵 谢谢你 没有循
  • 如果值不存在,则将数组对象推入另一个数组对象

    如果值不存在 需要将数组对象 arr1 的值推送到另一个数组对象 arr2 中 现有值不会推入另一个数组 var arr1 name fred name bill name ted name james var arr2 name spil
  • Android,当我在设备上安装应用程序时图标重复

    我尝试在我的设备上安装我开发的应用程序 Htcdesire 我发现该应用程序的图标是重复的 我需要改变什么才不会迟到发生这种情况 我怎样才能删除其中一个图标 感谢您的帮助 我今天遇到这个问题 我正在使用 Gradle 我发现有一个文件夹 b
  • Android,在 onClickListener 中使用 Toast

    我试图让 toast 在 onClickListener 内给定某些条件时显示一些文本 该应用程序无法在模拟器中运行 并且出现以下错误 void 无法转换为 Toast 我四处搜索 在这个论坛上找到了几个类似的问题和解决方案 但没有一个完全
  • Python 的 Requests 库中的 Session 对象线程安全吗?

    Python 的流行Requests该库在其主页上据说是线程安全的 但没有给出更多细节 如果我打电话requests session 然后我可以安全地将这个对象传递给多个线程 如下所示 session requests session fo
  • Java中模块的动态加载

    在 Java 中 我可以动态地将内容添加到类路径并加载类 动态 意味着无需重新启动我的应用程序 是否有一个已知的框架 库可以处理模块的动态加载 卸载而无需重新启动 通常的设置 尤其是 Web 应用程序 是负载均衡器 多个应用程序实例以及逐步
  • 填充控制台中的最后一行

    我想填充 更新控制台的整个底线 例子 static void Main string args Console BufferWidth Console WindowWidth Console BufferHeight Console Win
  • 恒定 FPS Android OpenGLES

    你好安卓开发者 我正在 Eclipse 中使用 OpenGLES 1 0 为 Android 开发一个简单的游戏 我使用 Samsung Galaxy S2 Android 2 3 作为开发设备 我有一个关于双核和使帧速率恒定的问题 因此
  • 在javascript中重置文本区域高度

    我有一个文本区域 自动调整大小 我想清除其所有内容 包括其高度 到目前为止我已经尝试过 document getElementById textarea value And document getElementById textarea
  • 如何在pandas中将一列分成三列

    我有一个数据框 如下所示 ID Name Address 1 Kohli Country India State Delhi Sector SE25 2 Sachin Country India State Mumbai Sector SE
  • 可以在触发器内动态创建 JOB 吗?

    该触发器的执行失败 它编译但一旦我执行指定的插入 gt 错误 create or replace TRIGGER AFT INSERT TMP TBL AFTER INSERT ON TMP TBL REFERENCING OLD AS O
  • 我可以让 postgres plpgsql 函数返回可变列记录吗?

    我想创建一个 postgres 函数来构建它的列集 即时返回 简而言之 它应该接受一个键列表 构建 每个键一列 并返回由该集组成的记录 列数是 简而言之 代码如下 CREATE OR REPLACE FUNCTION reports get
  • 在 Xcode 4.2、iOS 5.0 Beta 中创建 IPA 文件

    如何在 Xcode 4 2 iOS 5 0 测试版 中创建 ipa 文件 我已经开发了一个应用程序 但找不到权利文件 谁能告诉我创建 ipa 文件的过程 提前致谢 如果您拥有苹果开发者证书和相应的临时配置文件 则意味着可以使用 iOS 5
  • Python NetworkX - 为什么图表总是随机旋转?

    如果我使用 NetworkX 和 Matplotlib 多次生成相同的图表 它会在每一代中随机旋转 Run 1 Run 2 在不更改脚本或输入数据的情况下 每次生成图形时都会随机旋转 是否可以指定方向 随着图形变得更加密集 上面只是示例 但
  • 从导航抽屉操作栏中删除应用程序图标不起作用

    我正在开发一个有设计要求的应用程序 因为它应该只在 ActionBar 上有标题 而不是应用程序图标 我尝试了从 StackOverflow 找到的各种解决方案 例如 getActionBar setDisplayUseLogoEnable
  • Delphi - 从由非类型化指针填充的动态数组访问数据

    我在用着德尔福2009并不是说它对我正在做的事情有很大的影响 我想如果我还在的话我也会遇到同样的情况2007 我有一个 scsi 调用 它将数据输出到指针 查看它的方式是错误的 但我很难解释这一点 本来我用的是Move填充一个静态字节数组与