![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Абсолютно необъяснимый глюк
Franzy © (2009-04-30 15:05:00)Форма. На форме кнопка. По нажатию на кнопку производится обработка заранее подготовленных данных. Нажимаем первый раз - результат правильный. Нажимаем второй раз - результат правильный, причем точно такой же, как в первый раз. Нажимаем третий (четвертый, пятый...) раз - результат неправильный, и обратно каждый раз одинаковый!
Каждый раз входные данные одни и те же. В обработчике кнопки они никак не модифицируются. Только на их основе образуются новые данные. Эти новые данные каждый раз все честно обнуляются. В том числе всем дин. массивам присваиваю := nil.
Как такое может быть?!!!! Я в полном ступоре. Я понимаю, если бы каждый раз результат был разный или всегда одинаковый неправильный. Но тут при первом и втором нажатии результат А, а при всех последующих - результат Б. Ерунда какая-то!
Код очень объемный, поэтому не привожу. З.Ы. Нажатия кнопки в программе тоже никак не считаю. Все переменные, кроме временных и счетчиков, глобальные.
Sapersky (2009-05-08 16:40:00) [1]Проверил на разных версиях.
В D5, D7, и 2006 эффект есть. В 2009 - нет, т.е. всё нормально, вываливается с ошибкой независимо от размера записи.
В 2007-м, значит, заткнули дырку. Не прошло и 10 лет...
Cobalt (2009-05-07 22:07:00) [2]Хмм, только что проверил на Д2007 - никакого эффекта
Palladin (2009-05-03 15:39:00) [3]"А еще удивляются, почему я в церковь не хожу" (С) Догма
Юрий Зотов (2009-05-02 21:59:00) [4]Еще в тему.
Всегда преклонялся (не шучу) перед разработчиками компиляторов.
Эта ветка - тому подтверждение.
Спасибо.
Юрий Зотов (2009-05-02 21:54:00) [5]Братцы! Программеры! Я вас люблю!
За то, что вы такие.
Не шутка.
:o)
sniknik (2009-05-02 17:37:00) [6]> Потом закомментируйте i3...
а вот это действительно странно, т.е. наоборот странно пока не заментаришь... спасибо за предупреждение.
Sapersky (2009-05-02 16:15:00) [7]тут оптимизатор скорее всего выкинул вообще весь код
Нет, не выкинул.
приводи реальный код при глюке, чтобы можно было проверить. или указать истинного виновника.
Я уже разобрался там. Меня больше интересует работоспособность Range Check в расчёте на будущее, чтобы не искать глюки долго и мучительно.
А пример - да взять хоть [30] и переделать под записи.
type
TMyRec = record
i1, i2 : Integer;
i3 : Integer;
end;
TMyRecArray = array of TMyRec;
procedure TForm1.FormCreate(Sender: TObject);
var
A: TMyRecArray;
begin
SetLength(A, 10);
Caption := IntToStr(A[11].i1);
end;
Потом закомментируйте i3...
sniknik (2009-05-02 15:56:00) [8]> // проверки нет
тут оптимизатор скорее всего выкинул вообще весь код, не только проверку, т.к. результат не используется.
> а на реальном глюке молчал как партизан.
а ты тоже не молчи как партизан, распространяя только дезу, приводи реальный код при глюке, чтобы можно было проверить. или указать истинного виновника.
sniknik (2009-05-02 15:50:00) [9]> Так Borland сделал например, в TList.
да, и они наверняка проверяют сами, сколько там памяти под него реально выделено.
Amoeba (2009-05-02 15:33:00) [10]
> в "моем" с [0..32767] обманывать, т.к. заведомо определяем
> больший размер чем выделим, и Range checking не знает о
> реально выделенном размере
Так Borland сделал например, в TList.
Sapersky (2009-05-02 15:33:00) [11]Юрий Зотов © (02.05.09 12:48) [30]
Да, как выяснилось, иногдаработает...
У компилятора какая-то странная логика с вставкой этой проверки. Пытается оптимизировать, что ли, и выкидывает проверку если результат не используется (хотя даже в этом случае теоретически можно получить AV):
SetLength(arr, 3); Sum := 0;
For n:=0 to 3 do Inc(Sum, arr[n]); // проверки нет
А если добавить в конец Caption := InttoStr(Sum); - проверка работает.
Но самая неприятная, гм, "особенность" связана с массивами записей. Сейчас потестировал и выяснил, что Range Check работает только при размере записи <= 8 байт (???). Хотя, казалось бы, какая ему разница, длина-то массива лежит всегда в одном месте независимо от размера записи... и она всегда в элементах, не в байтах...
Недавно как раз "нарвался" именно с массивом записей. С почти такими же спецэффектами как у автора вопроса. Range Check радостно "завалил" программу на массиве-указателе вроде [18], а на реальном глюке молчал как партизан.
sniknik (2009-05-02 14:37:00) [12]> только спросил почему этот вариант - не динамический массив?
дальтоник? зеленый огонек от оранжевого отличить не можешь?
одно тип, другое указатель. пусть этот указатель и типизированный. причем если бы там был указатель на четко ограниченный размерностью массив, то Range checking тоже бы нормально срабатывал, но в "твоем" случае с [0..0] его приходится отключать т.к. заведомо вылазим за границы типа, в "моем" с [0..32767] обманывать, т.к. заведомо определяем больший размер чем выделим, и Range checking не знает о реально выделенном размере. (ну мы же специально его обманули)
а настоящий динамический массив включает в себя и длину, т.что есть по чему определять границу выхода и генерировать исключение.
это все так очевидно, не знаю даже зачем объяснять...
все одно что отвечать на вопрос почему 2 сваренных за рамы мотоцикла не являются машиной, ну, у них же тоже в сумме 4 колеса получилось...
Юрий Зотов (2009-05-02 12:59:00) [13]> Sapersky (02.05.09 12:11) [29]
> довольно бестолковая вещь этот Range checking, если в основном
> приходится думать, как его обойти...
А его и не надо обходить. Надо включить - и спокойно писать код, не заморачиваясь на эту тему. И если вдруг получим ERangeError, то будем обязаны сказать "Спасибо" за такой шикарный сервис. Потому что без него запросто могли бы нарваться на завуалированный глюк и до-о-олго искать, что это вдруг программа работает не так, как надо.
Пример - сабж. Лучше не придумаешь.
Юрий Зотов (2009-05-02 12:48:00) [14]
type
TIntArray = array of integer;
procedure TForm1.FormCreate(Sender: TObject);
var
A: TIntArray;
begin
SetLength(A, 10);
Caption := IntToStr(A[11]);
end;
В D7 Получаем ERangeError с сообщением "Range check error".
Sapersky (2009-05-02 12:11:00) [15]надо просто использовать динамические массивы и все, не выделываясь.
Гхм. Всё-таки, кто-нибудь реально проверял, работает Range checking с дин. массивами или нет?
У меня (D5) - не работает. И в хелпе написано "Long strings are not range checked", а дин. массивы по сути те же строки.
В общем, ИМХО, довольно бестолковая вещь этот Range checking, если в основном приходится думать, как его обойти...
Что касается "не выделываясь" - массивы-указатели (как я их называю) удобны тем, что к ним можно откастить изначально нетипизированный указатель (многие API возвращают данные в таком виде), и таким образом получить удобный доступ к данным.
Хотя можно откастить и к дин. массиву... если потом избегать обращения к его длине... и вручную прибить его, чтобы Delphi не пытался... но это уже хакерский выпендрёж :)
@!!ex (2009-05-02 11:49:00) [16]> [26] sniknik © (02.05.09 10:57)
> а со мной значит нет, когда я говорил про "обман" и подставил
> число гарантированно больше твоей 1000.
> не те слова сказал? у тебя есть "табу" на восприятие/понимание
> отдельных слов?
С чего вы взяли что "нет"? Я никак не комментировал, только спросил почему этот вариант - не динамический массив?
Юрий Зотов (2009-05-02 11:11:00) [17]> sniknik © (02.05.09 10:57) [26]
Не возражаю, чес-слово.
:о)
sniknik (2009-05-02 10:57:00) [18]> Согласен.
а со мной значит нет, когда я говорил про "обман" и подставил число гарантированно больше твоей 1000.
не те слова сказал? у тебя есть "табу" на восприятие/понимание отдельных слов?
> то проверку выключать не придется.
но для конкретно вот этого случая она будет мало что значить... т.к. при выделении памяти под 1000 никак не отреагирует на влезание в "запас" с 2000е поле например. что грозит теми же проблемами что у автора.
надо просто использовать динамические массивы и все, не выделываясь.
@!!ex (2009-05-02 09:48:00) [19]> [23] Anatoly Podgoretsky © (02.05.09 09:01)
> [24] Юрий Зотов © (02.05.09 09:38)
Согласен.
Юрий Зотов (2009-05-02 09:38:00) [20]> @!!ex ©
А если объявить так:
type
TIntArray = array[0..с_запасом] of integer;
то проверку выключать не придется.