Delphi 7 по сравнению с 2009 (и 2010) Рекордные размеры

У меня есть странная проблема при преобразовании кода из Delphi 7 to 2010. Это имеет отношение к записям. Запись определила ниже при калибровке в D7 432 байта, и в D2009 (и 2010), это 496. Я знаю, что легкое решение состоит в том, чтобы сделать это упакованной записью, затем все версии выходят к 426 байтам... Однако нам сохранили данные, где мы передали запись потоком, и теперь мы пытаемся считать те потоки с более новым языком.

TToTry = Record
 a,b,c,d : Extended;
 e,f,g,h : Extended;
 i : String[15];
 j,k,l,m,n,o,p,q,r,s,t : Array[1..3] of Extended; End;

В исследовании этой проблемы я создал другую запись, и, по любой причине, размеры являются тем же? Запись меньше, но она имеет совпадающие типы данных. но это выходит тот же размер во всех версиях языка.

TMyRecord = Record
Ext1  : Extended;
Ext2  : Extended;
Ext3  : Extended;
Ext4  : Extended;
Ext5  : Extended;
Ext6  : Extended;
Int1  : Integer;
Int2  : Integer;
char1 : AnsiChar;
char2 : AnsiChar;
MyString  : String[15];
Arr1  : Array[1..3] of Extended;
Arr2  : Array[1..3] of Extended; end;

У кого-либо есть понимание относительно того, почему одна запись так отличается, и другой то же? Что-то, чтобы сделать с выравниваниями границ байта в Delphi наверняка. но что изменилось так решительно от одной версии до следующего?

8
задан Mason Wheeler 8 July 2010 в 17:50
поделиться

4 ответа

Ну, первая проблема в том, что вы сохранили на диск неупакованную запись. Упаковка полей и массивов может меняться между выпусками продукта, потому что обычно расположение в памяти не видно за пределами процесса. Вы нарушили это правило.

Если значения по умолчанию для байтовой прокладки изменились между Delphi 7 и Delphi 2009, выясните, какими были значения по умолчанию в D7, и установите те же значения в Delphi 2009.

Также проверьте упаковку массива по умолчанию. Я не помню, есть ли для этого отдельная настройка.

Посмотрите на структуру записей в Delphi 2009 в режиме просмотра памяти отладки. Часть или весь дополнительный размер может быть обусловлен упаковкой самой записи (не полей внутри нее), чтобы при использовании записи в массиве элементы массива находились на границах быстрой машины.

Если ничего из этого не помогает, создайте временный упакованный тип записи в D2009 и вручную вставьте поля байтовой прокладки между полями фактических данных, пока размер записи и выравнивание полей не будут соответствовать макету D7. Дело не только в размере, но и в выравнивании полей. Считайте старый файл данных, используя эту временную упакованную запись. Затем перенесите данные поле за полем в "настоящий" тип записи в D2009 и запишите новый файл.

И пока вы это делаете, упакуйте этот тип записи в D2009, чтобы это не повторилось.

14
ответ дан 5 December 2019 в 05:55
поделиться

Я думаю, вы нашли функцию !. Я не смог получить разумный размер с вашим TToTry с D2007, поэтому мне пришлось искать адреса полей с помощью отладчика;

Во-первых, размер записи ниже,

{$A8}
type
  TToTry = record
    j: array[1..3] of Extended;
    k: array[1..3] of Extended;
    l: array[1..3] of Extended;
    m: array[1..3] of Extended;
  end;

равен 128 (32 * 4). Это ожидается, поскольку Extended составляет 10 байтов, 30 байтов будут выровнены по 32 байтам.

Но размер этой записи,

{$A8}
type
  TToTry = record
    j, k, l, m: array[1..3] of Extended;
  end;

составляет 120 (30 * 4). Это определенно неожиданно - поля все равно должны быть выровнены по 8-байтовой границе.

(У меня нет D7 для проверки, но я так думаю :)
Итак, теперь мы знаем, что сгруппированные поля упакованы, из этого следует, что выравнивание на D7 составляет 8 байтов, а ваша запись почти упакована;

TToTry = Record 
 a,b,c,d : Extended;    // 40 bytes (8*5)
 e,f,g,h : Extended;    // 40 bytes (8*5)
 i : String[15];        // 16 bytes (8*2)
 j,k,l,m,n,o,p,q,r,s,t: Array[1..3] of Extended; // 330 bytes
End; 

Компилятор дополняет 6 байтов до последней группы, чтобы она была кратной 8 и тогда вы получите 40 + 40 + 16 + 336 = 432 байта.

В D2009 / D2010 вы либо объявляете каждое поле - без их группировки, либо поведение изменяется.В любом случае упакуйте вашу запись и добавьте в конец фиктивное поле массива 6 байтов, и все будет в порядке.

Если это не сработает, просмотрите адреса полей вашей записи с помощью D7, затем создайте точную копию на D2009, используя упакованную запись и при необходимости используя фиктивные поля, после того как вы импортировали сохраненные данные, вы можете удалить фиктивные поля.

-
Я никогда не сталкивался с подобным поведением и нигде не могу найти его документально. Тем не менее, это настолько похоже на функцию, что я не решаюсь назвать это ошибкой. Я не знаю, как обстоят дела с D2009 или D2010, проверьте, так ли это. Если это так, чтобы получить ожидаемые результаты - не иметь наполовину упакованных записей - не поленитесь и объявляйте каждое поле отдельно для незапакованных записей.

7
ответ дан 5 December 2019 в 05:55
поделиться

Применение директивы {$ A8} не означает, что все поля записи выровнены по 8-байтовой границе - компилятор использует другую стратегию выравнивания. Например, размер

{$A8}
type
  TToTry = record
    a: byte;
    b: word;
    c: longword;
  end;

составляет 8 байтов в Delphi 2009, потому что компилятор выравнивает 2-байтовое значение по 2-байтовой границе, 4-байтовое значение по 4-байтовой границе, а единственное фактическое выравнивание в приведенном выше примере - Поле b выровнено по 2-байтовой границе.

Что касается исходного вопроса, что изменилось между Delphi 7 и Delphi 2009 - прочтите ответ Сертака Акьюза и мой комментарий к нему

2
ответ дан 5 December 2019 в 05:55
поделиться

Я считаю, что выравнивание по умолчанию было сделано шире. Укажите выравнивание 4 в более поздних версиях и посмотрите, получится ли оно так, как вы хотите.

В будущем вы должны убедиться, что любая запись, которая будет записана на диск, хранится упакованной, чтобы вы не были записаны таким образом.

Правка: Поскольку ни одно из выравниваний не работает (что меня удивляет), я бы вернулся к оригиналу и выяснил, как он на самом деле выровнен. Заполните запись чем-то вроде $FF, поместите данные и запишите их — посмотрите, где сохранилась $FFs. Возьмите новую запись, сделайте ее упакованной и добавьте наполнители, чтобы они соответствовали набивке в старой записи.

Одно: на самом деле это всего лишь одна запись? В прежние времена я использовал объекты в качестве поддельных записей с наследованием - ой, в точке наследования применялось нормальное выравнивание, и я не мог его остановить. В конечном итоге мне пришлось перейти к данным, чтобы принудительное выравнивание не нарушило мои данные. (Это было в API, это HAD, чтобы быть правым,Я не мог обрабатывать поля самостоятельно.)

2
ответ дан 5 December 2019 в 05:55
поделиться
Другие вопросы по тегам:

Похожие вопросы: