Проблем със "Set of ..." при Delphi 5
Накратко проблема е с променлива от тип "set of...." с 16..31 елемента и като искам да я инициализирам чрез ":=[]", то вместо да стане "[]" става [elm24..elem30]
Направих и следния тест:
Код:
type
Test=(t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16,t17,t18,t19,t20,t21,t22,t23,t24,t25,t26,t27,t28,t29,t30,t31,t32);
TTestSet= set of Test;
TTestSet1= set of 1..16;
TTestSet2= set of 1..32;
var
TestSet:TTestSet;
TestSet1:TTestSet1;
TestSet2:TTestSet2;
begin
TestSet:=[];//тук се получава все едно съм задал TestSet:=[t24..t30];
TestSet1:=[];//тук се получава все едно съм задал TestSet1:=[23..29];
TestSet2:=[];//тук всичко е нормално
....................
end;
Нулиране на TestSet получавам само така:
Fillchar(TestSet,SizeOf(TestSet),0);
Но след това проверката "TestSet<>[]" винаги дава True, а "TestSet=[]" - False ????
Лошото е, че на много места използвам такъв тип променливи и ако трябва да променям всички или да ги проверявам за проблеми ще ми отнеме много време. Въпросната грешка я открих случайно при Debug на част от кода.
След още тестове установих следното:
TTestSet2= set of 1..15;//дължина(SizeOf) 2 байта -> няма проблеми
TTestSet3= set of 1..16;//дължина(SizeOf) 4???? байта -> ИМА проблеми
TTestSet4= set of 1..31;//дължина(SizeOf) 4 байта -> ИМА проблеми
TTestSet5= set of 1..39;//дължина(SizeOf) 5 байта -> няма проблеми
TTestSet6= set of 1..47;//дължина(SizeOf) 6 байта -> няма проблеми
TTestSet7= set of 1..55;//дължина(SizeOf) 7 байта -> няма проблеми
TTestSet32= set of 1..255;//дължина(SizeOf) 32 байта -> няма проблеми
След инициализиране:
TestSet3:=[];
TestSet4:=[];
то ShowMessage('ts3='+IntToStr(Longint(TestSet3))+';' +'ts4='+IntToStr(Longint(TestSet4)));
ми връща: "ts3=1065353216;ts4=1065353216"
=>проблема е само при 4 байтовите set-ове. ?
Чудя се аз ли бъркам някъде или има проблем с Delphi 5?
След като направих Copy->Paste на "тестовия" код на друго място в програмата, то там всичко си работеше по нормалния начин??? Единствено дължината на TestSet3 пак беше 4 байта вместо 3???
В имената на "тестовите" променливи и в начина им на дефиниране и използване няма никаква разлика на двете места, но защо се получават различни резултати?
Възможно ли е някаква директива на компилатора да предизвиква тези аномалии? (доста комбинации направих и с директивите но проблема си остава) :081:
Единственото логично обяснение според мен е, че понякога "[]" не е празно и затова при проверката "if TestSet<>[]" и при инициализиране чрез "TestSet:=[]" не се получава това което очаквам.
Вече се замислям дали начина ми на работа с множества не е погрешен. И как да съм сигурен на другите места в програмата какво се случва и дали всичко работи както трябва?
Моля за помощ и благодаря предварително на тези, които ще помогнат.
Може и да почерпя някой път. :) :Drinks:
Благодаря и на тези, които са прочели написаното, защото май не се получи "накратко". :)
Re: Проблем със "Set of ..." при Delphi 5
Имам инсталирано само Delphi 7 и под него горния код работи както се очаква. Не намирам подобна публикувана грешка за Delphi 5 или по-ранни. Сигурен съм обаче, че ако нещо такова имаше, самият аз щях да изплача.
Сигурно ли е, че тези грешки ги получаваш в "чиста" програма - т.е. ползваща само System и никакви други юнити? Най-добре - само горния код. Питам, защото Delphi компилатора "скрито" дефинира:
var
Empty1: set of byte = [];
Empty2: set of word = [];
Empty4: set of longword = [];
...
и т.н. до 32 байта.
и ползва горните променливи (всъщност инициализирани константи) за присъединяване и сравняване с празно множество на променлива заемаща съответната дължина байтове и е възможно някой друг код без да иска да променя паметта на точно някоя от тези константи (в твоя случай май е точно тази с дължина 4 байта).
Както забелязваш, не се дефинира променлива с три байта и това е нарочно - за оптимизация. Set of 1..16 заема 17 бита - когато е числова областта на множеството, Delphi ползва битовете със съответните номера (set of 16..33 е 34 бита) - ето защо 1..16 заема 3, което значи, че Delphi ползва 4 байта.
Виж също какво ще стане ако пишеш TestSet:=(TestSet*[t1]) - [t1]; - би трябвало да даде празно множество. Но го гледай в дебугера или в програмата като интеджер.
Пробвай също така да изключищ оптимизациите - {$OPTIMIZATION OFF} - току-виж това бил проблема.
Re: Проблем със "Set of ..." при Delphi 5
Пробвай също и:
Project \ Options \ Compiler \ Record Field Alignment - по дефол е 8 байта....
Re: Проблем със "Set of ..." при Delphi 5
kamenf и The_Wizard благодаря ви за отговорите.
@The_Wizard ,
"Aligned record fields" при мен е винаги изключено, защото проекта е още от Delphi 1. :)
Цитат:
Първоначално публикувано от kamenf
............
Виж също какво ще стане ако пишеш TestSet:=(TestSet*[t1]) - [t1]; - би трябвало да даде празно множество. Но го гледай в дебугера или в програмата като интеджер.
Пробвай също така да изключищ оптимизациите - {$OPTIMIZATION OFF} - току-виж това бил проблема.
@kamenf,
При "TestSet:=(TestSet*[t1]) - [t1];" - дава празно множество но проверката "TestSet=[]" връща "False". :help
Оптимизацията я включвам само при компилация "за клиенти". :)
По-горе съм написал, че този проблем го има само на някои места в проекта, т.е. в "чиста" програма го няма проблема. :)
Затова мисля, че вероятно(99% :) ) е това което казваш:
Цитат:
Първоначално публикувано от kamenf
..............
Delphi компилатора "скрито" дефинира:
var
Empty1: set of byte = [];
Empty2: set of word = [];
Empty4: set of longword = [];
...
и т.н. до 32 байта.
и ползва горните променливи (всъщност инициализирани константи) за присъединяване и сравняване с празно множество на променлива заемаща съответната дължина байтове и е възможно някой друг код без да иска да променя паметта на точно някоя от тези константи (в твоя случай май е точно тази с дължина 4 байта).
.................
Не успях да намеря къде се дефинират "Empty1...Empty32", пък и променливи с тези имена със сигурност не използвам. Вероятно в Delphi 5 не се казват така и ще ти бъда благодарен ако може да ми кажеш къде да търся повече информация за set-вете в Delphi 5 или къде се дефинират "Empty1..Empty32". :)
Re: Проблем със "Set of ..." при Delphi 5
Това беше условно - няма да намериш тези дефиниции - затова казах "скрито". Но можеш да погледнеш с CPU дебугера асемблерския код на въпросното присъединяване или сравнение и после по адреса измъкнат от там да инсталираш хардуерен брейкпойнт по запис в памет и така да хванеш кой я променя.
Re: Проблем със "Set of ..." при Delphi 5
Цитат:
Първоначално публикувано от kamenf
Това беше условно - няма да намериш тези дефиниции - затова казах "скрито". Но можеш да погледнеш с CPU дебугера асемблерския код на въпросното присъединяване или сравнение и после по адреса измъкнат от там да инсталираш хардуерен брейкпойнт по запис в памет и така да хванеш кой я променя.
Жалко, щеше да е много по-лесно, ако не беше "скрито". :)
С асемблер не съм се занимавал от 1990г. и ще те помоля за "малко" помощ. :help
Ето какво ми дава CPU дебугера:
Код:
problem.pas.743: TestSet:=[];
00A252CC A1BC63A200 mov eax,[име_на_процедурата + $2CC8]
00A252D1 8945C4 mov [ebp-$3c],eax
problem.pas.744: TestSet2:=[];
00A252D4 66A1BC63A200 mov ax,[$00a263bc]
00A252DA 668945BE mov [ebp-$42],ax
problem.pas.745: TestSet3:=[];
00A252DE A1BC63A200 mov eax,[име_на_процедурата + $2CC8]
00A252E3 8945BA mov [ebp-$46],eax
problem.pas.746: TestSet5:=[];
00A252E6 8B05E063A200 mov eax,[име_на_процедурата + $2CEC]
00A252EC 8945B1 mov [ebp-$4f],eax
00A252EF 8A05E463A200 mov al,[име_на_процедурата + $2CF0]
00A252F5 8845B5 mov [ebp-$4b],al
Код:
var
TestSet= set of (t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16,t17,t18,
t19,t20,t21,t22,t23,t24,t25,t26,t27,t28,t29,t30,t31,t32);
TestSet2= set of 1..15;
TestSet3= set of 1..16;
TestSet5= set of 1..39;
Проблема е при "problem.pas.743: TestSet:=[];" и "problem.pas.745: TestSet3:=[];"
Предполагам, че това "[име_на_процедурата + $2CC8]" е някакъв относителен адрес за мястото, където се намира "[]", но:
Как "да инсталирам хардуерен брейкпойнт по запис в паметта" при Delphi 5? :081: (Никога не съм използвал тази възможност и дали ще може при Delphi 5)
Какъв е адреса на "[]"?
Re: Проблем със "Set of ..." при Delphi 5
Борланд казва това:
Set types
A set is a bit array where each bit indicates whether an element is in the set or not. The maximum number of elements in a set is 256, so a set never occupies more than 32 bytes. The number of bytes occupied by a particular set is equal to
(Max div 8) - (Min div 8) + 1
where Max and Min are the upper and lower bounds of the base type of the set. The byte number of a specific element E is
(E div 8) - (Min div 8)
and the bit number within that byte is
E mod 8
where E denotes the ordinal value of the element.
може да се окаже че си открил бъг...... :)
Re: Проблем със "Set of ..." при Delphi 5
Така... ще се опитам по памет. Първо натискаш F8 - да стартира програмата, но да спре на първата инструкция. Второ: от менюто View\Debug Windows\Breakpoints трябва да се показва прозореца Breakpoints. Ако не се показва от там - намери от къде точно се показва. В прозореца Breakpoints - десен бутон на мишката и "Add -> Data Breakpoint". Излиза диалог в който трябва да въведеш адрес от паметта, който искаш да се следи и колко байта да се следят - достатъчно е да въведеш само адреса и големината и ще прекъсва на всяка инструкция която променя паметта в този адрес. От твоя пример адреса (на []) е [име_на_процедурата + $2CC8] или @(PChar(@име_на_процедурата) + $2CC8)^ - последното можеш да го видиш колко е в "Evaluate/Modify..." диалога (обикновено се пуска с Ctrl+F7), или спри на реда "mov eax,[име_на_процедурата + $2CC8]" и отгоре на CPU прозореца трябва да имаш редче от рода на "[$00123456] = $00000000" (в квадратните скоби е адреса на въпросното []). Вивеждаш за Length - 4. После пускаш програмата да върви и гледай кога и защо прекъсва - на накое от тези места трябва да е проблема.
Re: Проблем със "Set of ..." при Delphi 5
Цитат:
Първоначално публикувано от kamenf
Така... ще се опитам по памет. Първо ....
@kamenf, явно имаш много добра памет. :)
Всичко е точно така, както си го описал. Но сигурно аз бъркам някъде, защото при "Add Data Breakpoint" за адреса който намирам не се създава Breakpoint, :( мога да създам само "Address Breakpoint". :)
Сутринта ще опитам пак, че този проблем със "set-овете" ме дразни като "муха в стая" и докато не разбера каква точно е причината ще ми "бръмчи" в главата. :)
Re: Проблем със "Set of ..." при Delphi 5
Ако така не стане (а явно няма, или поне не при Delphi 5, защото доколкото виждам от асемблера, паметта е в участъка на кода), можеш да опиташ и друго - ръчния метод ;) - като намериш адреса на 4-байтовия [] по един от горните методи, отвори си "Watch List"-a (View\Debug Windows\Watches) и в него - десен бутен -> Add Watch -> "PInteger($онзи_адрес)^" (трябва да показва 0 като стойност), после изпълнявай програмата на порции да хванеш кога ще престане да показва 0 и така лека-полека изолирай частта от кода, който променя тази памет. Разбира се, същото можеш да го гледаш и в CPU прозореца (в долната рамка - Goto Address...), ама не е толкова изолирано.
А ако не ти се занимава, може да направиш и един генерален уъркараунд (баааси, как изглежда на кирилица ;) )- декларирай си константа (или константи - за всеки множествен тип който използваш):
const
Empty: TWantedSet = [];
и после я(ги) замени навсякъде в кода, където използваш [].
Re: Проблем със "Set of ..." при Delphi 5
малко трудно ще сложиш брекпойнт на мемори менаджера, но както и да е....
тука има нещо свързано с ord типевете ми се струва.
Re: Проблем със "Set of ..." при Delphi 5
Май ще се окаже "мисия невъзможна" откриването на проблема. :081:
Чрез "Add Watch" на "PInteger($00A2691C)^", след това при стартиране с F8 на програмата и спиране на първата инструкция в "dpr" файла (преди да се изпълни "Application.Initialize;"), то вече в адреса на "[]" е заредена стойността, която по-късно се присвоява при "нулиране" на TestSet.
В друга процедура в която съм копирал същия "тестов код" адреса на "[]" е друг и за него всичко е нормално в "Add Watch" на "PInteger($006EE9B8)^". :081:
Кой и кога е записал нещо в тази клетка от паметта остава в тайна. :)
Когато ми остане повече свободно време ще си дефинирам константи за изпозваните видове set-ове и ще заменя навсякъде "[]" със съответната константа, че вече доста време отделих на този проблем. :)
@kamenf, като гледам часа в който пишеш във форума, май наистина "дочакваш утрото", т.е. това, което си написал като подпис е вярно. :)
Цитат:
Първоначално публикувано от The_Wizard
малко трудно ще сложиш брекпойнт на мемори менаджера, но както и да е....
тука има нещо свързано с ord типевете ми се струва.
@The_Wizard, проблем със сигурност има, но защо се случва на мен и то в момент в който имам много задачи и всички са с краен срок "вчера" :).
Re: Проблем със "Set of ..." при Delphi 5
закон за всемирната гадост...... :)
Драсни маил на супорта на борланд и им обясни проблема.