Есть ли разница между массивом и упакованным массивом в Delphi? - PullRequest
15 голосов
/ 03 января 2011

В 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 различны - их можно «распаковать», чтобыразмер структуры больше, чем сумма размеров полей из-за выравнивания полей.)

Ответы [ 2 ]

26 голосов
/ 03 января 2011

Это не имеет практического эффекта в 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 имеют некорректное выравнивание для типов, определенных внутри них, и с тех пор им приходилось жить с этим.) С другой стороны, в целях совместимости с форматом файла упаковка может быть оправдана, но есть там также много других проблем, связанных с выбором типа (например, Integer составлял 2 байта в 16-битном Delphi, но 4 байта впоследствии).

Delphi пытается использовать C-совместимые правила для выравнивания. В прошлом здесь были некоторые ошибки (особенно с такими записями, как TRec = запись A, B: расширенный конец; по сравнению с TRec = запись A: расширенный; B: расширенный конец;), но эти ошибки должны быть исправлены сейчас

0 голосов
/ 17 июня 2013

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 

Итак, для этого документаупаковано.

...