【问题标题】:Are there any difference between array and packed array in Delphi?Delphi中的数组和打包数组有什么区别吗?
【发布时间】:2011-06-02 19:25:31
【问题描述】:

在 C/C++ 中你总是有

SizeOf(array[N] of T) = N * SizeOf(T);

在 Pascal/Delphi 中,您可以使用 'packed array' 来确保上述断言是正确的,但是 'packed' 说明符对 Delphi 中的数组有任何实际价值吗?我无法创建“未打包”数组的示例,数组似乎总是“打包”:

type
  A = array[0..2] of Byte;
  B = array[0..99] of A;
  C = packed record
    C1, C2, C3: Byte;
  end;
  D = array[0..99] of C;

procedure TForm10.Button1Click(Sender: TObject);
begin
  Assert(SizeOf(A) = 3);
  Assert(SizeOf(B) = 300);
  Assert(SizeOf(D) = 300);
end;

(C/C++ 结构和 Delphi 记录是不同的 - 它们可以被“解包”,因此由于字段对齐,结构的大小大于字段大小的总和。)

【问题讨论】:

  • 我猜如果没有packed 修饰符,delphi 编译器的未来版本可能会使用非紧凑数组。就我个人而言,当且仅当我关心确切的内存布局时,我才使用packed

标签: arrays delphi alignment packed


【解决方案1】:

在Delphi中没有实际作用。它可以合理影响的唯一类型是具有最奇怪的对齐和大小组合的类型Extended,它的大小为 10,对齐为 8。但是,Extended 的数组基本上已经打包(尽管它们仍然有对齐为 8;如果 packed 指令的工作方式与记录上的一样,则它们的对齐方式为 1)。

为什么我说Extended 的数组是它可能影响的唯一类型?没有其他的 Delphi 类型,内置的或您可以组合的,其大小不是其对齐的整数倍(撇开旧版本的 Delphi 和一些错误)。对齐是通过填充使记录变大的东西。它导致字段被隔开,以便每个字段都从一个偏移量开始,该偏移量是其类型对齐的整数倍。在与数组类似的情况下,只涉及一种类型,如果大小已经是类型对齐的倍数,则不需要填充。

这是一个程序,它显示Extended 如何影响大小和对齐方式,具体取决于它是否包含在记录中;您可以将packed 添加到数组中,看看它没有区别:

type
  TWrap = record
    X: Extended;
  end; // field size=10, align=8, => actual size=16

  TArr1 = array[1..3] of TWrap; // 3*16 => size=48, align=8
  TArr2 = array[1..3] of Extended; // 3 * 10 => size=30, align=8

  TRec1 = record
    A: Byte;
    B: TArr1;
  end;

  TRec2 = record
    A: Byte;
    B: TArr2;
  end;

var
  x: TRec1;
  y: TRec2;
begin
  Writeln('Size of TArr1: ', SizeOf(TArr1));
  Writeln('Alignment of TArr1: ', Integer(@x.B) - Integer(@x.A));
  Writeln('Size of TArr2: ', SizeOf(TArr2));
  Writeln('Alignment of TArr2: ', Integer(@y.B) - Integer(@y.A));
end.

更多关于对齐和packed 的文字:packed 有另一种效果(对记录),而不仅仅是保证没有添加填充:它还将记录标记为自身对齐为 1。这有负面影响导致它在其他地方使用时经常错位的效果。出于语言/操作系统互操作性的目的,只有在其他语言不使用操作系统对齐规则(通常意味着 C 对齐规则)的情况下,才应使用打包指令。 (请注意,某些 Windows API 标头对于其中定义的类型的对齐方式不正确,并且从那时起就不得不忍受它。)另一方面,出于与文件格式兼容的目的,打包可能是合理的,但是有还有很多其他问题,关于类型选择(例如,整数在 16 位 Delphi 中是 2 个字节,但随后是 4 个字节)。

Delphi 尝试使用与 C 兼容的规则进行对齐。过去,这里有一些错误(特别是 TRec = 记录 A,B:扩展结束;与 TRec = 记录 A:扩展;B:扩展结束;),但现在应该修复这些错误

【讨论】:

  • 非常有趣,谢谢。我希望 Extended 能够在 64 位编译器中存活,并且不会被别名为 double。
  • 遗憾的是,没有记录打包暗示对齐=1 的记录。至少当我遇到这个问题时,这不是我最后一次查看!
【解决方案2】:

Delphi XE Help 对动态数组这么说

动态数组内存布局(仅限 Win32):

偏移内容

-8  32-bit = reference-count  
-4  32-bit = length indicator (number of elements)  
0..Length * (size of element) -1 = array elements 

所以,它被那个文档打包了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-01-21
    • 1970-01-01
    • 2010-10-10
    • 2016-08-10
    相关资源
    最近更新 更多