У меня есть странная проблема при преобразовании кода из 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 наверняка. но что изменилось так решительно от одной версии до следующего?
Ну, первая проблема в том, что вы сохранили на диск неупакованную запись. Упаковка полей и массивов может меняться между выпусками продукта, потому что обычно расположение в памяти не видно за пределами процесса. Вы нарушили это правило.
Если значения по умолчанию для байтовой прокладки изменились между Delphi 7 и Delphi 2009, выясните, какими были значения по умолчанию в D7, и установите те же значения в Delphi 2009.
Также проверьте упаковку массива по умолчанию. Я не помню, есть ли для этого отдельная настройка.
Посмотрите на структуру записей в Delphi 2009 в режиме просмотра памяти отладки. Часть или весь дополнительный размер может быть обусловлен упаковкой самой записи (не полей внутри нее), чтобы при использовании записи в массиве элементы массива находились на границах быстрой машины.
Если ничего из этого не помогает, создайте временный упакованный тип записи в D2009 и вручную вставьте поля байтовой прокладки между полями фактических данных, пока размер записи и выравнивание полей не будут соответствовать макету D7. Дело не только в размере, но и в выравнивании полей. Считайте старый файл данных, используя эту временную упакованную запись. Затем перенесите данные поле за полем в "настоящий" тип записи в D2009 и запишите новый файл.
И пока вы это делаете, упакуйте этот тип записи в D2009, чтобы это не повторилось.
Я думаю, вы нашли функцию !. Я не смог получить разумный размер с вашим 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, проверьте, так ли это. Если это так, чтобы получить ожидаемые результаты - не иметь наполовину упакованных записей - не поленитесь и объявляйте каждое поле отдельно для незапакованных записей.
Применение директивы {$ 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 - прочтите ответ Сертака Акьюза и мой комментарий к нему
Я считаю, что выравнивание по умолчанию было сделано шире. Укажите выравнивание 4 в более поздних версиях и посмотрите, получится ли оно так, как вы хотите.
В будущем вы должны убедиться, что любая запись, которая будет записана на диск, хранится упакованной, чтобы вы не были записаны таким образом.
Правка: Поскольку ни одно из выравниваний не работает (что меня удивляет), я бы вернулся к оригиналу и выяснил, как он на самом деле выровнен. Заполните запись чем-то вроде $FF, поместите данные и запишите их — посмотрите, где сохранилась $FFs. Возьмите новую запись, сделайте ее упакованной и добавьте наполнители, чтобы они соответствовали набивке в старой записи.
Одно: на самом деле это всего лишь одна запись? В прежние времена я использовал объекты в качестве поддельных записей с наследованием - ой, в точке наследования применялось нормальное выравнивание, и я не мог его остановить. В конечном итоге мне пришлось перейти к данным, чтобы принудительное выравнивание не нарушило мои данные. (Это было в API, это HAD, чтобы быть правым,Я не мог обрабатывать поля самостоятельно.)