Форум: "Основная";
Текущий архив: 2010.03.28;
Скачать: [xml.tar.bz2];
ВнизDelphi 2009 - запись с вариантной частью Найти похожие ветки
← →
Чайник © (2009-06-30 21:02) [0]Перенос проекта из D7 в D2009:
Объявление типа:TtcMixture = record //Состав газовой смеси
Name : string[64];
MixtureKind : TtcMixtureKind;
Ro, Mu, Cp, Cv, Hs : Extended;
case Vid : Boolean of
False : (N2, Ar, O2, H2O, CO, CO2, CH4 : Extended);
True : (Comp : array[1..7] of Extended);
end;
В D7 все работало нормально, т.е. операторы вида
Mix.N2 := 0.7809 и Mix.Сomp[0] := 0.7809 эавивалентны.
В D2009 - такое впечатление, что вариантные части в разных областях памяти - Mix.N2 и Mix.Сomp[0] не зависимы друг от друга.
Что делать?
← →
Чайник © (2009-06-30 21:15) [1]Заменил record на packed record - заработало.
И что бы это значило?
← →
Юрий Зотов © (2009-07-01 00:44) [2]> И что бы это значило?
Поля N2, Ar, O2, H2O, CO, CO2, CH4 выравниваются, а массив packed, его элементы не выравниваются.
← →
Германн © (2009-07-01 01:03) [3]
> Юрий Зотов © (01.07.09 00:44) [2]
>
> > И что бы это значило?
>
> Поля N2, Ar, O2, H2O, CO, CO2, CH4 выравниваются, а массив
> packed, его элементы не выравниваются.
>
Точнее это значит, что в Дельфи есть опция компилятора $A. И она может настраиваться.
А packed следует применять сейчас только в особых случаях. Например, когда данная запись должна иметь возможность рассматриваться "с точностью" до байта.
P.S.
И не массив packed, Юр. А запись packed.
← →
Юрий Зотов © (2009-07-01 01:20) [4]> Германн © (01.07.09 01:03) [3]
> И не массив packed, Юр. А запись packed.
Лучше не спорь. И людей не путай.
← →
Германн © (2009-07-01 01:39) [5]
> Юрий Зотов © (01.07.09 01:20) [4]
>
> > Германн © (01.07.09 01:03) [3]
>
> > И не массив packed, Юр. А запись packed.
>
> Лучше не спорь. И людей не путай.
>
Спорить с тобой? Я не на столько дурак. :)
Но людей я вроде как не путаю.
Речь в сабже шла о packed record, а не о packed array.
Хотя, иногда, можно и с ЮЗ поспорить. :)
← →
Юрий Зотов © (2009-07-01 08:24) [6]> Германн © (01.07.09 01:39) [5]
Спорить можно с кем угодно, если по делу. Но не в данном случае, потому что ты просто не понял.
Сабж я читал внимательно, что описатель packed был применен к записи, е не к массиву - учел. Именно в этом и дело - смотри, что получается.
type
TRec = record
case boolean of
False : (F1, F2: extended);
True : (A : array[1..2] of extended);
end;
TPackRec = packed record
case boolean of
False : (F1, F2: extended);
True : (A : array[1..2] of extended);
end;
var
R: TRec;
PR: TPackRec;
=================
for i := 1 to 2 do // Заполняем обе записи
begin
R.A[i] := i;
PR.A[i] := i
end;
Учитывая, что SizeOf(extended)=10, теперь получим, что R.F1<>R.A[1] и R.F2<>R.A[2], хотя PR.F1=PR.A[1] и PR.F2=PR.A[2]. Дело в том, что массив всегда packed, даже и без явного объявления (как ни странно, но почему-то это так). И выходит, что в записи R поля F1 и F2 не совпадают с элементами массива A (поскольку поля F1 и F2 невыравнены, а массив выравнен), а в записи PR - совпадают (поскольку и эти поля, и массив выравнены).
Вообще говоря, это различие между R и PR должно проявляться во всех версиях Delphi. Почему у автора оно не провляется в D7 и проявляется в D2009 - непонятно. Можно предположить 2 причины:
1. В настройках компилятора D7 у него проставлено дефолтное выравнивание полей записей на границу байта (что эквивалентно packed), а в D2009 - другое.
2. Каждый компилятор что-то с выравниванием химичит, причем каждый по-своему. Как ни фантастично это предположение выглядит (и похоже на баг), оно, тем не менее, правдоподобно - потому что в D7 разница между R и PR действительно не проявляется при любом дефолтном выравнивании. Только что проверил это на практике (при дефолтном выравнивании на границу двойного слова):
procedure TForm1.FormCreate(Sender: TObject);
var
i: integer;
begin
for i := 1 to 2 do
begin
R.A[i] := i;
PR.A[i] := i;
ListBox1.Items.Add(FloatToStr(R.A[i])); // 1 и 2, как и должно быть
ListBox2.Items.Add(FloatToStr(PR.A[i])) // 1 и 2, как и должно быть
end;
ListBox1.Items.Add(FloatToStr(R.F1)); // 1, как НЕ должно быть
ListBox1.Items.Add(FloatToStr(R.F2)); // 2, как НЕ должно быть
ListBox1.Items.Add(IntToStr(SizeOf(R))); // 24, как и должно быть
ListBox2.Items.Add(FloatToStr(PR.F1)); // 1, как и должно быть
ListBox2.Items.Add(FloatToStr(PR.F2)); // 2, как и должно быть
ListBox2.Items.Add(IntToStr(SizeOf(PR))); // 20, как и должно быть
end;
← →
Юрий Зотов © (2009-07-01 08:33) [7]Вообще-то, для всех было бы полезно эту странность обсудить. Завел ветку:
http://delphimaster.net/view/15-1246422749/
← →
oxffff © (2009-07-01 08:54) [8]
> В D7 все работало нормально, т.е. операторы вида
>
> Mix.N2 := 0.7809 и Mix.Сomp[0] := 0.7809 эавивалентны.
Я не еще не запускал Delphi 2009. Но первое что бросилось в глаза это
Сomp[0] и
True : (Comp : array[1..7] of Extended);
end;
?
← →
brother © (2009-07-01 09:09) [9]> Вообще-то, для всех было бы полезно эту странность обсудить.
> Завел ветку:
> http://delphimaster.net/view/15-1246422749/
тогда эту закрыть не мешало бы...
← →
MBo © (2009-07-01 09:17) [10]D2006, Align 8
type
TRec1 = record
case boolean of
False : (F1: Extended; F2: extended);
True : (A : array[1..2] of extended);
end;
TRec2 = record
case boolean of
False : (F1, F2: extended);
True : (A : array[1..2] of extended);
end;
TPackRec = packed record
case boolean of
False : (F1: Extended; F2: extended);
True : (A : array[1..2] of extended);
end;
var
R1: TRec1;
R2: TRec2;
PR: TPackRec;
begin
Memo1.Lines.Add(Format("R1 Size %d F2 Offset %d A2 Offset %d",[SizeOf(R1), Integer(@R1.F2) - Integer(@R1), Integer(@R1.A[2]) - Integer(@R1)]));
Memo1.Lines.Add(Format("R2 Size %d F2 Offset %d A2 Offset %d",[SizeOf(R2), Integer(@R2.F2) - Integer(@R2), Integer(@R2.A[2]) - Integer(@R2)]));
Memo1.Lines.Add(Format("PR Size %d F2 Offset %d A2 Offset %d",[SizeOf(PR), Integer(@PR.F2) - Integer(@PR), Integer(@PR.A[2]) - Integer(@PR)]));
вывод
R1 Size 32 F2 Offset 16 A2 Offset 10
R2 Size 24 F2 Offset 10 A2 Offset 10
PR Size 20 F2 Offset 10 A2 Offset 10
разница в смещении поля F2 между R1 и R2 объясняется этим:
If two fields share a common type specification, they are packed even if the declaration does not include the packed modifier and the record type is not declared in the {$A-} state. Thus, for example, given the following declaration
type
TMyRecord = record
A, B: Extended;
C: Extended;
end;
A and B are packed (aligned on byte boundaries) because they share the same type specification. The compiler pads the structure with unused bytes to ensure that C appears on a quadword boundary.
← →
Юрий Зотов © (2009-07-01 09:44) [11]> MBo © (01.07.09 09:17) [10]
Да, это объясняет поведение в D7 - но в D2009, видимо, сделано иначе.
← →
Anatoly Podgoretsky © (2009-07-01 09:49) [12]> Чайник (30.06.2009 21:15:01) [1]
Ты чего то не договариваешь, не сообщаешь какой то важной информации.
Для указаного случая не важно packed или нет, разница может проявляться только при использование низкоуровневых методов доступа и при импорте/экспорте.
← →
Юрий Зотов © (2009-07-01 10:50) [13]> MBo © (01.07.09 09:17) [10]
Кстати, и поведение в D7 тоже не совсем объясняет (SizeOf = 24).
← →
Sapersky (2009-07-01 11:57) [14]Кстати, и поведение в D7 тоже не совсем объясняет (SizeOf = 24).
Finally, the compiler rounds the total size of the record upward to the byte boundary specified by the largest alignment of any of the fields.
У Extended выравнивание - 8.
В хелпе D5, кстати, написано что 2. Тем не менее, в примере [10] все результаты совпадают с 2006-м (т.е. реально 8).
← →
vuk © (2009-07-01 12:19) [15]Собственно, объявление записи как packed от бага избавляет. А вообще, на будущее, видимо, стоит попробовать для записей пользоваться не вариантными секциями, а свойствами.
← →
Чайник © (2009-07-01 23:58) [16]
> Anatoly Podgoretsky © (01.07.09 09:49) [12]
> Ты чего то не договариваешь,
> не сообщаешь какой то важной информации.Для указаного случая
> не важно packed или нет, разница может проявляться только
> при использование низкоуровневых методов доступа и при импорте/экспорте
Да нет, ничего особенного не использую:function GetAthmosphere(const T, P: Extended; MKind : TtcMixtureKind): TtcMixture;
var tmpMix : TtcMixture;
begin
tmpMix.Name := "Сухой воздух";
tmpMix.MixtureKind := thpVolumeProcent;
tmpMix.N2 := 0.7809;
tmpMix.Ar := 0.0093;
tmpMix.O2 := 0.2095;
tmpMix.H2O := 0.0;
tmpMix.CO := 0.0;
tmpMix.CO2 := 0.0003;
tmpMix.CH4 := 0.0;
Result := tmpMix;
end;
...
...
for i:=1 to N_COMP do begin
FGasProp.grdMix.Cells[0,i] := aMixName[i];
FGasProp.grdMix.Cells[1,i] := FloatToStr(tmpMix.Comp[i]);
end;
Кстати, посмотрел в настройки - действительно, в D7 стоит Record Field Alignment=8, а в D2009 - QuadWord.
Но! Перепробовал все возможные предлагаемые варианты (QWord, DWord, Word, Byte)- ничего не помогает, баг остается.
← →
Германн © (2009-07-02 00:42) [17]
> Юрий Зотов © (01.07.09 09:44) [11]
>
> > MBo © (01.07.09 09:17) [10]
>
> Да, это объясняет поведение в D7 - но в D2009, видимо, сделано
> иначе.
>
Может Борис скажет где в документации на Д2006 есть те строки, которые он привел в конце своего поста. А автор (или ещё кто, у коно есть Д2009) посмотрит что написано в таком же месте в документации на Д2009. Тогда будет ясно баг это или новое правило.
← →
Германн © (2009-07-02 00:49) [18]
> vuk © (01.07.09 12:19) [15]
>
> Собственно, объявление записи как packed от бага избавляет.
> А вообще, на будущее, видимо, стоит попробовать для записей
> пользоваться не вариантными секциями, а свойствами.
Для некоторых новых проектов это наверно подойдёт.
Для некоторых проектов (неважно старых или новых) это не подойдёт никогда. Имхо.
А проблемы с переносом старых проектов на новые версии Дельфи всё равно останутся.
← →
MBo © (2009-07-02 04:23) [19]>Может Борис скажет где в документации на Д2006 есть те строки, которые он привел в конце своего поста
в хелпе Index-Look for - packed - Record types reference - часть Record Types в топике Internal Data Formats
напрямую темы Internal Data Formats и Record Types в хелпе 2006 не ищутся
Internal Data Formats
← →
Чайник © (2009-07-02 10:08) [20]А вот что написано в хелпе 2009 (обратите внимание на последнюю фразу):
To ensure proper alignment of the fields in an unpacked record type, the compiler inserts an unused byte before fields with an alignment of 2, and up to three unused bytes before fields with an alignment of 4, if required. Finally, the compiler rounds the total size of the record upward to the byte boundary specified by the largest alignment of any of the fields.
If two fields share a common type specification, they are packed even if the declaration does not include the packed modifier and the record type is not declared in the {$A-} state. Thus, for example, given the following declaration
type
TMyRecord = record
A, B: Extended;
C: Extended;
end;
A and B are packed (aligned on byte boundaries) because they share the same type specification. The compiler pads the structure with unused bytes to ensure that C appears on a quadword boundary.
When a record type is declared in the {$A-} state, or when the declaration includes the packed modifier, the fields of the record are not aligned, but are instead assigned consecutive offsets. The total size of such a packed record is simply the size of all the fields. Because data alignment can change, it"s a good idea to pack any record structure that you intend to write to disk or pass in memory to another module compiled using a different version of the compiler.
← →
MBo © (2009-07-02 12:11) [21]угу, в 2006 то же самое
Страницы: 1 вся ветка
Форум: "Основная";
Текущий архив: 2010.03.28;
Скачать: [xml.tar.bz2];
Память: 0.52 MB
Время: 0.005 c