Delphi中的数组和压缩数组有什么区别吗?

时间:2011-01-03 11:18:37

标签: arrays delphi alignment packed

在C / C ++中你总是有

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

在Pascal / Delphi中你可以使用'packed array'来确保上面的断言是真的,但'packed'说明符对Delphi中的数组有什么实际价值吗?我不能创建一个'unpacked'数组的例子,数组似乎总是'打包':

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记录不同 - 它们可以'解包',因此由于字段的对齐,结构的大小大于字段大小的总和。)

2 个答案:

答案 0 :(得分:26)

在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.

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

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

答案 1 :(得分:0)

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 

所以,通过那份文件,它已被打包。