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

Arrays Delphi中的数组和压缩数组有什么区别吗?,arrays,delphi,alignment,packed,Arrays,Delphi,Alignment,Packed,在C/C++中,您总是 SizeOf(array[N] of T) = N * SizeOf(T); 在Pascal/Delphi中,您可以使用“压缩数组”来确保上述断言为真,但是“压缩”说明符对Delphi中的数组有实际价值吗?我无法创建“未打包”数组的示例,数组似乎总是“打包”的: type A = array[0..2] of Byte; B = array[0..99] of A; C = packed record C1, C2, C3: Byte; end;

在C/C++中,您总是

SizeOf(array[N] of T) = N * SizeOf(T);
在Pascal/Delphi中,您可以使用“压缩数组”来确保上述断言为真,但是“压缩”说明符对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记录是不同的-它们可以“解包”,以便由于字段对齐,结构的大小大于字段大小之和。)

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

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

下面是一个程序,它显示了
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
还有另一个作用(对记录),而不仅仅是保证没有添加填充:它还将记录标记为自身对齐为1。这有一个负面影响,即在其他地方使用时,会导致其经常错位。出于语言/操作系统互操作性的目的,只有在其他语言未使用操作系统对齐规则(通常指C对齐规则)的情况下,才应使用压缩指令。(请注意,某些Windows API标头对其中定义的类型的对齐方式不正确,并且从那时起就不得不使用它。)另一方面,为了与文件格式兼容,打包可能是合理的,但在类型选择方面也存在许多其他问题(例如,在16位Delphi中,整数是2个字节,但随后是4个字节)


Delphi尝试使用与C兼容的规则进行对齐。在过去,它在这里有一些错误(特别是像TRec=record A,B:Extended end;与TRec=record A:Extended;B:Extended end;)这样的记录,但是这些错误现在应该被修复了

动态阵列内存布局(仅限Win32):

抵销内容

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

因此,通过该文档,它是打包的。

我想如果没有
打包的
修改器,未来版本的delphi编译器可能会使用非压缩数组。就我个人而言,我使用
打包的
,只要我关心确切的内存布局。非常有趣,谢谢。我希望扩展将在64位编译器中继续存在,并且不会被化名为doub令人遗憾的是,没有记录表明记录对齐=1的打包。至少这不是我最后一次看到这个问题了!