![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Range Check Error [D5, Win95/98]
MegaVolt © (2006-03-30 18:02:00)Почему в первой функции при включенной проверке выхода за границы диапазонов вылазит ошибка а во второй нет
function F1(s:string):cardinal;
begin
Result:=(StrToInt(s) and $FF) shl 24;
end;
function F2(s:string):cardinal;
begin
Result:=(StrToInt(s) shl 24) and $FF000000;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
ShowMessage(IntToStr(F1('192')));
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
ShowMessage(IntToStr(F2('192')));
end;
причём если сдвиг делать на меньшее число байт то всё нормально.
Rouse_ (2006-03-31 11:15:00) [1]Ну в принципе да...
MegaVolt (2006-03-31 11:12:00) [2]ИМХО ничего там не вычитается :) Просто если смотреть на первый бит как на знаковый то число отрицательное. А если считать число положительным то это и есть положительное число :)
Rouse_ (2006-03-31 10:38:00) [3]Ну и в конце концов - если отключена данная проверка, то ты всеравно получишь результат: просто отрицательное значение вычтеца из 4294967295
и получиться число которое соответствует типу Cardinal
Rouse_ (2006-03-31 10:35:00) [4]За переполнение отвечает флаг OF. по нему тоже идет проверка...
А почему не учитывается - ну ты нашел у кого спросить :)
Спрашивай у разработчиков компилятора :)
MegaVolt (2006-03-31 10:29:00) [5]>Вот эти две инструкции проверяют - не является ли полученное число отрицательным, и если оно является таковым - то выполняется BoundErr.
А почему не учитывается что наше число впринципе не может быть отрицатеьным. Т.к. cardinal только положителен.
И почему во втором случае корый действительно при сдвиге неизвесно какого числа может привести к переполнению компилятор молчит? Т.е. сдвиг числа большего чем 255 привелёт к переполнению.
Rouse_ (2006-03-31 10:14:00) [6]
> И зачем нужен RangeCheck, если я знаю, что мне нужно, а
> компилятор лишь думает, что я этого не знаю. Проще ставить
> {$R+} там где есть какая-то неуверенность в коде.
Вот такой код при отключенной проверке выхода за пределы диапазона приведет к AV, т.к. цикл будет крутиться от нуля до 4294967295
var
I: Cardinal;
begin
List.Count := 0;
I := 0 to List.Count - 1 do
begin
ListItems[I] := 'qwe';
end;
end;
Rouse_ (2006-03-31 10:00:00) [7]Тут все очень просто:
Cardinal является у нас unsigned 32-bit, диапазон 0..4294967295
При выполнении данного кода генерируются такие инструкции:
mov eax,[ebp-$04]
call StrToInt
mov ebx,eax
and ebx,$000000ff
shl ebx,$18
test ebx,ebx
jns $0049cd2a
call @BoundErr
Вот эти две инструкции
test ebx,ebx
jns $0049cd2a
проверяют - не является ли полученное число отрицательным, и если оно является таковым - то выполняется BoundErr.
Признак отрицательного значения у нас находиться в флаге SF, который после выполнения инструкции shl ebx,$18 становиться равным единице.
Результат выполнения данной функции равен: -1073741824
Измени обьявление функции на такое: function F1(s:string):Integer;
и ошибка исчезнет :)
Defunct (2006-03-31 04:28:00) [8]Конкретно в таких случаях я поступаю так:
{$R-}
Хотя чаще просто выключаю Range Checking вообще в опциях проекта.
И зачем нужен RangeCheck, если я знаю, что мне нужно, а компилятор лишь думает, что я этого не знаю. Проще ставить {$R+} там где есть какая-то неуверенность в коде.
Германн (2006-03-31 01:11:00) [9]
> Pavia © (30.03.06 22:25) [2]
>
> Во второй функции дельфи подставляет
> StrToInt(s:string):int64;
> А в первой
> StrToInt(s:string):integer;
> Так что, во второй запас большой.
Есть StrToInt, а есть StrToInt64. Это две большие разницы. И дельфи врядли сможет сама "подставить" вместо одной другую. Да и не в этой функции дело.
Мне непонятен сам смысл сабжа, в котором присутствует функция and, которая может только уменьшить результат, а никак не увеличить.
Pavia (2006-03-30 22:25:00) [10]Во второй функции дельфи подставляет
StrToInt(s:string):int64;
А в первой
StrToInt(s:string):integer;
Так что, во второй запас большой.
MegaVolt (2006-03-30 18:06:00) [11]Причём если передать число большее чем байт вторая функция всё равно не ругается хотя за границу cardinal вылам точно.