【问题标题】:Is CompareMem suitable for comparing two arrays for equality?CompareMem 是否适合比较两个数组是否相等?
【发布时间】:2013-06-19 15:02:33
【问题描述】:

我需要比较给定数组的所有项是否相同。

目前,我有以下代码:

Type
  TD = array [0..1] of TDateTime;

var A: TD;
    B: TD;
begin
  A[0] := Date-1;   A[1] := Date+1;
  B[0] := Date-1;   B[1] := Date+1;

  if CompareMem(@A, @B, SizeOf(TD)) then
    Showmessage('Equals')
  else
    Showmessage('Differ');

这工作正常,但由于 CompareMem 是用汇编语言编写的,我(还)无法理解它的作用。

CompareMem 是一种有效的方式来做我想做的事吗?另外,我想知道是否适用于字符串、整数等每种数据类型。

【问题讨论】:

  • 使用 CompareMem 仅适用于简单数据类型。如果数据是托管类型,例如对象、字符串、动态数组等,那么您只是在比较指针值。
  • 一般答案是否,因为数组元素可能是aligned。但是,如果您打算永远使用 Borland 编译器和 Intel 架构,您可以安全地做到这一点(这是因为 Borland 数组隐含 packed)。

标签: arrays delphi compare


【解决方案1】:

这不是用汇编写的...如果所有内存都被无间隙的数组项填充,则比较内存是有效的。一般来说,如果

1) 所有的数组内存都被无间隙的数据填充(间隙可能包含垃圾并导致假阴性)。

1.1。这应该由packed array 关键字强制执行,如果编译器不会忽略它

1.2 如果 SizeOf(A[1]) 为 2,4,8,16 等,则应该发生这种情况

但您最好通过使用具有不同模式的 FillChar 进行单元测试来涵盖这一点 - 它们会模仿垃圾,然后用匹配值手动填充数组元素,然后使用 CompareMem 检查元素是否擦除了所有预先填充的垃圾。

2) 数组元素只包含简单的值类型,不包含引用类型。

字符、整数、双精度、短字符串、固定大小的数组或由这些组成的记录 - 都是简单类型。

所有其他字符串、指针、对象、接口、动态和开放数组——仅仅是指向外部数据的指针,不能“按内存”进行比较

您可以阅读http://docwiki.embarcadero.com/Libraries/XE2/en/System.Finalize 以获得更多提示。过程/函数的汇编器实现也是一个不错的话题,因为它涵盖了不同 Delphi 数据类型的二进制表示

【讨论】:

  • 您的第二个代码是汇编代码,但您谈到了您最初引用的代码,即 Pascal。好吧,CompareMem 正在做它名副其实的事情。制作 PByte 变量并循环比较值并移动两个指针 - 您将拥有 功能上 等效的纯帕斯卡代码。 asm 例程对速度进行了非常优化,但基本上您可以通过简单的循环逐个字节地比较它来实现它的等价物。也许你可以从 FPC 中得到现成的 Pure Pascal 实现,但它真的很琐碎。两个 PByte 指针和一个循环 - 就是这样。
  • 那么,对字符串数组执行此操作的唯一方法是对循环中的每个项目执行比较?
  • 是的。您可以通过预先计算字符串的哈希并存储哈希+字符串而不是单独存储字符串来解决这个问题 - 在某些可以提高速度的任务中,但在其他任务中则不然。
  • 您对填充的讨论存在缺陷。 Delphi 数组总是打包的。但记录可能不是。当它们不是时,比较内存不起作用,因为您比较没有意义的填充字节。
  • 另外,记录不是简单的类型。记录是结构化类型。
【解决方案2】:

CompareMem 只是进行逐字节比较。 CompareMem 对值相等性测试无效的主要方式有两种:

  1. 被测试的类型包含填充。
  2. 被测试的类型是或包含引用类型。

你问的是数组。由于数组是always packed,它们不包含填充。由于您是在比较数组值,所以问题可以集中在数组的元素上。

当且仅当数组元素是不包含填充字节且不包含引用类型的值类型时,数组的值比较才是合适的。

这是所有简单值类型的情况。

对于记录,你需要检查记录是否包含引用类型。这必须是递归检查。记录是否包含包含引用类型的记录,等等。然后你必须寻找填充。一发现padding,CompareMem的使用就不合适了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-08-18
    • 2017-09-22
    • 2021-09-14
    • 2023-03-11
    • 2010-12-05
    • 2016-03-06
    相关资源
    最近更新 更多