Текущий архив: 2006.12.24;
Скачать: CL | DM;
Вниз
Вычисление булевых выражений Найти похожие ветки
← →
pasha_golub © (2006-11-30 11:37) [0]Прямо мистика какая-то. В среде включено укороченное вычесление, по умолчанию.
Имеется код:
If Assigned(APrevFocusedNode) and APrevFocusedNode.Values[tlcCompositeModified.ItemIndex] then
...
APrevFocusedNode = nil на момент выполнения этой инструкции. По идее, не должно происходить дальнейшего вычисления. А оно происходит, и ясен пень, с вылетом на AV.
Думал какие-то настройки локальные вмешались. Прямо перед строкой этой поставил:{$BOOLEVAL OFF}
Не помогло. Поставил{$B-}
, эффект тот же самый.
Попробовал перестроить условие:If Assigned(APrevFocusedNode) then
If APrevFocusedNode.Values[tlcCompositeModified.ItemIndex] then
Так работает без ошибки.
Вопрос: почему так происходит?
← →
vuk © (2006-11-30 11:43) [1]Попробовать можно следующие варианты:
1. Отключить оптимизацию
2. Заменить Assigned на сравнение с nil
← →
pasha_golub © (2006-11-30 11:46) [2]
> 1. Отключить оптимизацию
Попробовал. Не помогло.
Сейчас второе...
← →
pasha_golub © (2006-11-30 11:48) [3]
If (APrevFocusedNode <> nil) and APrevFocusedNode.Values[tlcCompositeModified.ItemIndex] then
Тоже не сработало
← →
pasha_golub © (2006-11-30 11:52) [4]
function VarToBoolDef(const V: Variant; const ADefault: boolean): boolean;
begin
Result := ADefault;
if V <> Null then try
Result := V;
except
Result := ADefault
end;
end;
If (APrevFocusedNode <> nil) and VarToBoolDef(APrevFocusedNode.Values[tlcCompositeModified.ItemIndex],False) then
А вот если так, то работает.
← →
umbra © (2006-11-30 11:56) [5]наверное APrevFocusedNode <> nil
← →
pasha_golub © (2006-11-30 12:00) [6]
> наверное APrevFocusedNode <> nil
>
http://www.farata.kr.ua/FTP/other/debug.png
Триста раз проверил.
← →
pasha_golub © (2006-11-30 12:04) [7]Я так понимаю дело в том, что:
property Values[Index: Integer]: Variant read GetValue write SetValue;
И, наверное, происходят какие-то манипуляции с подготовкой этих вариантов. Может быть такое?
← →
Юрий Зотов © (2006-11-30 12:04) [8]Паш, надеюсь, после изменения опций ты делал Build (причем Build All), а не просто Compile?
← →
vuk © (2006-11-30 12:05) [9]А можно увидеть что конкретно сгенерил компилятор?
← →
pasha_golub © (2006-11-30 12:10) [10]
> Юрий Зотов © (30.11.06 12:04) [8]
>
> Паш, надеюсь, после изменения опций ты делал Build (причем
> Build All), а не просто Compile?
>
Да, конечно.
> vuk © (30.11.06 12:05) [9]
>
> А можно увидеть что конкретно сгенерил компилятор?
В смысле CPU окошко? Не нашел как скопипастить, сейчас сделаю скрин.
← →
vuk © (2006-11-30 12:12) [11]>Не нашел как скопипастить, сейчас сделаю скрин.
Не, ну совсем обленился! :o)
← →
pasha_golub © (2006-11-30 12:13) [12]Окошечно ЦПУ:
http://www.farata.kr.ua/FTP/other/debug1.png (9Кб)
← →
pasha_golub © (2006-11-30 12:14) [13]
> Не, ну совсем обленился! :o)
Думал, сначалу руками набрать, но потом подумал, что лучше исключить фактор кривизны. ;0)
← →
wal © (2006-11-30 12:21) [14]Вот оно, так как второе значение - вариант, то первое тоже приводится к варианту, над ними выполняется and, результат приводится boolean. Почему именно так - хз, видимо где-то какой то приоритет битовых операций над логическими.
← →
vuk © (2006-11-30 12:23) [15]Я может чего не понял, но по ходу пьессы, получается, что не вариант приводится к boolean, а результат первого сравнения без всякого анализа конвертируется в вариант (VarFromBool), потом принудительно при помощи VarAnd производится логическая операция со второй частью, где все и обламывается.
← →
pasha_golub © (2006-11-30 12:24) [16]
> wal © (30.11.06 12:21) [14]
Действительно. Интересный факт оказывается. И налететь на него можно с размаху, и не понять в чем дело.
← →
Суслик © (2006-11-30 12:27) [17]А опциях всего проекта что стоит по поводу bool eval?
← →
Суслик © (2006-11-30 12:28) [18]Дельфи, кстати, какой?
← →
wal © (2006-11-30 12:29) [19]
> [16] pasha_golub © (30.11.06 12:24)
Порылся в хелпе:
Except for comparisons, which always return a Boolean result, any operation on a variant value returns a variant result. If an expression combines variants with statically-typed values, the statically-typed values are automatically converted to variants.
← →
pasha_golub © (2006-11-30 12:30) [20]
> Суслик © (30.11.06 12:27) [17]
>
> А опциях всего проекта что стоит по поводу bool eval?
>
В первом же посте писал: отключено complete boolean eval
← →
pasha_golub © (2006-11-30 12:32) [21]
> Суслик © (30.11.06 12:28) [18]
>
> Дельфи, кстати, какой?
>
D7
> wal © (30.11.06 12:29) [19]
Thanks. Надо себе в память заложить!!!
← →
Суслик © (2006-11-30 12:32) [22]
> [20] pasha_golub © (30.11.06 12:30)
прости, не заметил :)
← →
Суслик © (2006-11-30 12:32) [23]Да... факт интересный.
← →
vuk © (2006-11-30 12:33) [24]Кстати, а что будет, если написать
If Assigned(APrevFocusedNode) and (APrevFocusedNode.Values[tlcCompositeModified.ItemIndex] = true) ?
← →
pasha_golub © (2006-11-30 12:35) [25]
> vuk © (30.11.06 12:33) [24]
> If Assigned(APrevFocusedNode) and (APrevFocusedNode.Values[tlcCompositeModified.
> ItemIndex] = true)
Сработало, как и ожидалось. Но тут на лицо явное мошенничество. :)
← →
vuk © (2006-11-30 12:39) [26]>Но тут на лицо явное мошенничество. :)
Нет. Таким образом мы просто сделали преобразование в другом месте и получили сравнение уже двух булевых переменных.
← →
Anatoly Podgoretsky © (2006-11-30 12:40) [27]> vuk (30.11.2006 12:23:15) [15]
Налицо полное вычисление выражения.
← →
Anatoly Podgoretsky © (2006-11-30 12:41) [28]> pasha_golub (30.11.2006 12:30:20) [20]
По приведено снимку видно, что ни о каких boolean eval говорить не приходится.
← →
pasha_golub © (2006-11-30 12:43) [29]
> Anatoly Podgoretsky © (30.11.06 12:41) [28]
В первом посте сказано:
> В среде включено укороченное вычесление
Кстати, ошибку заметил. :) Вычисление...
← →
Anatoly Podgoretsky © (2006-11-30 12:45) [30]> pasha_golub (30.11.2006 12:35:25) [25]
Ну ты понял, никаких булевых вычислений нет если вторая часть вариант, а во втором случае есть, за счет простого трюка.
Но решение ты знаешь, когда не уверен в булевых вычислениях делай в два приема
if 1 then
if 2 then
Это гарантирует и полную независимост от настроек и от подобных фокусов по замене логических выражений на операции с вариантами.
← →
vuk © (2006-11-30 12:47) [31]to Anatoly Podgoretsky © (30.11.06 12:40) [27]:
>Налицо полное вычисление выражения.
Похоже, что компилятор решил, что для вычисления выражения нужно все вычисления делать в вариантах и уже потом получать из этого boolean. А and он в данном случае мог вообще трактовать не как логический, а как побитовый. Судя по тому что он сгенерировал, так и вышло.
← →
Суслик © (2006-11-30 12:50) [32]Я все-таки не понял, *зачем* компилятор вычислял второе выражение?
Ну ясное дело, что variant"ы. Но полностью то вычислять зачем
Признаюсь я до конца не понял приведенную выше ссылку на доку:
Except for comparisons, which always return a Boolean result, any operation on a variant value returns a variant result. If an expression combines variants with statically-typed values, the statically-typed values are automatically converted to variants.
Ну сказано здесь, что он к вариантам приводит. Но это имеется в виду, что он код генерит, который приводит. Зачем генерить код, который вычисляет второй параметр?
Объясните пжлст.
← →
wal © (2006-11-30 12:53) [33]
> Зачем генерить код, который вычисляет второй параметр?
Чтобы в результате and вернуть вариант, единственное исключение, когда в результате не вариант - операции сравнения.
← →
Суслик © (2006-11-30 12:54) [34]Я может быть тупой, но вычислять то зачем?
Вернуть можно и не вычисляя.
← →
Суслик © (2006-11-30 12:55) [35]Т.е. я не вижу из доки того факта, что вычисляться должны оба выражения.
← →
Суслик © (2006-11-30 12:55) [36]Собственно интерес простой - может это баг?
Тогда его запостить нужно в QC.
← →
pasha_golub © (2006-11-30 13:03) [37]
> Суслик © (30.11.06 12:55) [36]
>
> Собственно интерес простой - может это баг?
> Тогда его запостить нужно в QC.
В принципе, я тоже склоняюсь к данному мнению.
← →
wal © (2006-11-30 13:04) [38]
> [34] Суслик © (30.11.06 12:54)
Потомучто Variant(False) и False - вещи разные
← →
wal © (2006-11-30 13:08) [39]
> [36] Суслик © (30.11.06 12:55)
Это поведение описано в хелпе, какой же это баг?
← →
Anatoly Podgoretsky © (2006-11-30 13:17) [40]> pasha_golub (30.11.2006 12:43:29) [29]
Включено, только ни о каких логических вычислениях и речи нет, вот пример, который ты обозвал трюком, как раз честный, идет логическое вычисление и слева и справа Boolean
← →
Anatoly Podgoretsky © (2006-11-30 13:19) [41]> vuk (30.11.2006 12:47:31) [31]
Да посчитал и он имеет на это право, поскольку справа вариант, а там может быть и не Boolean
← →
Anatoly Podgoretsky © (2006-11-30 13:21) [42]> Суслик (30.11.2006 12:50:32) [32]
А что ему делать, если выражение не логическое?
Там получается следующее
Variant(1) and Variant2
Левую половину можно преобразовать в Вариант всегда, а правую в логическое не всегда.
← →
Anatoly Podgoretsky © (2006-11-30 13:22) [43]> wal (30.11.2006 13:04:38) [38]
А еще лучше это в выглядит для True и еще лучше
Variant(False) и string
← →
TUser © (2006-11-30 13:30) [44]Возможно отладчик глючит. Пару раз было, вроде. Лесился приемами типа
var i: integer;
begin
i := integer (YourPointer);
ShowMessage (inttostr (i));
конечно, не отладчик, но замена ему.
← →
wal © (2006-11-30 13:35) [45]
> [44] TUser © (30.11.06 13:30)
Да вроде разобрались уже, отладчик не причем
← →
Anatoly Podgoretsky © (2006-11-30 13:42) [46]> TUser (30.11.2006 13:30:44) [44]
Да ничего не глючит, у него нормальный указатель, CPU это доказывает и правильно написаный код тоже работает, это тот где справа Expr = True
← →
Суслик © (2006-11-30 13:43) [47]
> [39] wal © (30.11.06 13:08)
>
> > [36] Суслик © (30.11.06 12:55)
> Это поведение описано в хелпе, какой же это баг?
Где описано? Какое конкретное слово? А?
Описано, что преобразует, но не описано, что вычисляет полностью.
← →
Суслик © (2006-11-30 13:51) [48]
> [39] wal © (30.11.06 13:08)
>
> > [36] Суслик © (30.11.06 12:55)
> Это поведение описано в хелпе, какой же это баг?
Может быть там еще в доке что-то есть по этому поводу? Т.к. фраза сама по себе не говорит о том, что должно быть полное вычисление.
Ты где это нашел? Какой раздел?
PS. В BDS, кстати тоже самое.
← →
wal © (2006-11-30 14:00) [49]
> [48] Суслик © (30.11.06 13:51)
Ради тебя специально хелп перерыл, с тебя пиво.
Boolean operators
...
Note
If either operand involves a variant, the compiler always performs complete evaluation (even in the {$B-} state).
← →
Суслик © (2006-11-30 14:06) [50]
> [49] wal © (30.11.06 14:00)
Спасибо.
Это уже говорит о сабже!
Не знал, кстати.
Дя и вариантами не пользуюсь :)
(будешь в пятницу, будет пиво).
← →
Anatoly Podgoretsky © (2006-11-30 14:11) [51]> wal (30.11.2006 14:00:49) [49]
Можно считать данный пост последней точкой
← →
wal © (2006-11-30 14:13) [52]
> [50] Суслик © (30.11.06 14:06)
> (будешь в пятницу, будет пиво).
Как-нибудь в следующий раз. На паравоз не успеваю.
Хотя мне и без этого насилия над хелпом еще из [19] стало понятно, что получаем мы Boolean(Variant(Param1) and Param2), что в данном случае and не является логической операцией, и, соответственно, short-circuit Boolean evaluation к ней неприменим.
← →
pasha_golub © (2006-11-30 14:57) [53]
> wal © (30.11.06 14:00) [49]
> Note
>
> If either operand involves a variant, the compiler always
> performs complete evaluation (even in the {$B-} state).
Спасибо. Хотя я бы это назвал не Note, a Warning. :)
← →
Суслик © (2006-11-30 15:29) [54]
> Хотя мне и без этого насилия над хелпом еще из [19] стало
> понятно, что получаем мы Boolean(Variant(Param1) and Param2),
> что в данном случае and не является логической операцией,
> и, соответственно, short-circuit Boolean evaluation к ней
> неприменим.
Какой гениальный :)
Вообще в кодеtype
o = class
dd: string;
function v: variant;
end;
function o.v;
begin
result := true;
dd := "24123541";
end;
procedure TForm1.Button1Click(Sender: TObject);
var
oo: o;
begin
oo := nil;
if (oo <> nil) and oo.v then
begin
showmessage("a");
end;
end;
Им ничего не мешало построить иной код
Unit1.pas.45: if (oo <> nil) and oo.v then0046B6B9 8D45E4 lea eax,[ebp-$1c]
0046B6BC 837DF800 cmp dword ptr [ebp-$08],$00
0046B6C0 0F95C2 setnz dl
0046B6C3 E81899FAFF call @VarFromBool
например тут проверить, что результат @VarFromBool равен true.0046B6C8 8D45E4 lea eax,[ebp-$1c]
0046B6CB 50 push eax
0046B6CC 8D55D4 lea edx,[ebp-$2c]
0046B6CF 8B45F8 mov eax,[ebp-$08]
0046B6D2 E879FFFFFF call o.v
0046B6D7 8D55D4 lea edx,[ebp-$2c]
0046B6DA 58 pop eax
0046B6DB E850B0FAFF call @VarAnd
0046B6E0 8D45E4 lea eax,[ebp-$1c]
0046B6E3 E88873FAFF call @VarToBool
0046B6E8 84C0 test al,al
0046B6EA 740A jz $0046b6f6
← →
Суслик © (2006-11-30 15:30) [55]Топик все же очень полезный - век живи, иногда читай www.delphimaster.ru, век учись.
← →
wal © (2006-11-30 15:49) [56]
> например тут проверить, что результат @VarFromBool равен
> true.
И что? Сразу вернуть False? and в данном контексте не булева операция, и не обязана возвращать Variant(True) или Variant(False)
← →
Alx2 © (2006-11-30 15:58) [57]>wal © (30.11.06 15:49)
А "if" разве не говорит о булевости?
← →
wal © (2006-11-30 16:02) [58]
> [57] Alx2 © (30.11.06 15:58)
Вот результат потом и приводится к Boolean, а сам оператор and разве "знает", что над ним if?
← →
Alx2 © (2006-11-30 16:09) [59]>wal © (30.11.06 16:02) [58]
> а сам оператор and разве "знает", что над ним if?
Это вроде как работа компилятора. Он же "знает", что применять если if a and b then ...
и если просто a := a and b;
побитовый and и логический как-то определены в синтаксисе. А здесь, мне кажется, выглядит как исключение из правил.
← →
Alx2 © (2006-11-30 16:12) [60]>wal © (30.11.06 16:02) [58]
Хотя неоднозначность есть - что-то вроде разницы между
if (a and b) и if (a) and (b) в случае вариантов
← →
Суслик © (2006-11-30 16:19) [61]
> [58] wal © (30.11.06 16:02)
>
> > [57] Alx2 © (30.11.06 15:58)
> Вот результат потом и приводится к Boolean, а сам оператор
> and разве "знает", что над ним if?
И что ты так защищаешь компилятор? Это его дело - оптимизацией заниматься.
Вона - есть среды выполнения, которые перекомпилируют на лету код циклов, если на то есть необходимость.
-------
Ну ничего страшного. Примем данный факт за фичу. Не сказать, чтобы природа фичи ясна было. Но таково состояние компилитора. Их (разработчиков) право. Радует то, что данный факт указан в документации. Я уже привык, что многие тонкие моменты они в доке не любят обозначать. А тут на те - есть :)
← →
wal © (2006-11-30 16:20) [62]
> Это вроде как работа компилятора. Он же "знает" ...
Откуда? Он только на этапе проверки (в if) или присваивания (в :=) приводит результат к нужному типу.
← →
Суслик © (2006-11-30 16:26) [63]Ладно, давай не спорить - все равно правды не найдем.
Я не согласен с такой семантикой. Ты, судя по всему, согласен.
Ну и ладно.
----
Они так сделали, потому что так было легче. Их можно понять. Хорошо, что задокументировали. Молодцы. Можно привыкнуть к любой странности, лишь бы была специфицирована.
← →
wal © (2006-11-30 16:26) [64]
> [61] Суслик © (30.11.06 16:19)
> И что ты так защищаешь компилятор?
Да ничуть, просто разобрали конкретный пример, разобрали поведение компилятора, для себя я счел его правильным, к тому же, как выяснилось, это поведение документировано.
← →
Alx2 © (2006-11-30 16:28) [65]>Суслик © (30.11.06 16:19)
>И что ты так защищаешь компилятор?
Вовсе не защищаю.
>Это его дело - оптимизацией заниматься.
:)
>wal © (30.11.06 16:20) [62]
>Откуда? Он только на этапе проверки (в if)
>или присваивания (в :=) приводит результат к нужному типу.
Да, с вариантами, кажется, получается, так. Неприятная особенность.
← →
Суслик © (2006-11-30 16:28) [66]
> Да ничуть, просто разобрали конкретный пример, разобрали
> поведение компилятора, для себя я счел его правильным, к
> тому же, как выяснилось, это поведение документировано.
Ну не надо :)
Ты сказал, что тебе было ясно это почти сразу. Ну я тебя гением обозвал. С этого то и началось. Хорошо - не гений.
Тут логика, со стороны разработчиков компилятора одна - так было сделать существенно проще. Почему? Не знаю. Но думаю, что это так.
Страницы: 1 2 вся ветка
Текущий архив: 2006.12.24;
Скачать: CL | DM;
Память: 0.64 MB
Время: 0.038 c