Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Абсолютно необъяснимый глюк


Страницы:   1 2 3

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;
то проверку выключать не придется.


Страницы:   1 2 3

Наверх

Титульная страница Поиск, карта сайта Написать письмо