Pull to refresh

Comments 17

"не надо так"… Я прямо даже и не знаю, как сказать.


А в сях есть способ написать


dword r = a — b;
if (was_overflow) r=0;


чтоб скомпилировалось в проверку флага после вычитания?

Как в Rust'е, да? Типа checked_sub. Если я не ошибаюсь, то нет. Вычитание неотрицательных DWORD чисел само по себе уже опасно. Как мы можем сравнивать результат с нолём в отрицательную сторону?

Я не знаю, как другие бы сделали это лаконично, я бы сперва числа сравнил друг с другом перед вычитанием. Ради интереса, я сейчас изучаю Rust, и стал на эти проблемы чаще обращать своё внимание.
В стандартных пока что нет (работы по добавлению ведутся), но в GCC и clang давно уже да.
Спасибо.

Интересно, а

dword r = a-b;
if (b > a) return 0; else return r;

соптимизируется на ASM уровне само или нет?
Несложно проверить через Compiler Explorer.

GCC (O2):
mov eax, edi
mov edx, 0
sub eax, esi
cmp edi, esi
cmovb eax, edx
ret

Clang (O2):
xor eax, eax
sub edi, esi
cmovae/cmovge eax, edi (ae for uint32_t, ge for int32_t)
ret

Остальные компиляторы можете попробовать по аналогии там же.
да, уже подёргал там в разных вариациях.
ни один из них не свернулся в sub + jo/jno…

При этом вариант с __builtin_sub_overflow сворачивается хорошо
godbolt.org/z/sq63d3
Зато на ARM получается отлично:
subs w8, w0, w1 # вычесть из w0 (a) w1 (b), положить результат в w8 (a-b)
csel w0, wzr, w8, lo # сравнить содержимое wzr (ноль) с w8 (a-b), если строго меньше, то положить в w0 (возвращаемое из функции значение) wzr (ноль), иначе w8 (a-b)
ret
В каком варианте сырка?
Что-то GCC/arm с -O3 мне даже вариант с builtin выдаёт что-то странное.
Кстати, а чем не устроил вариант выше с cmov? Он быстрее, чем sub/jo, потому что в нем вообще переходов нет (и потому нельзя их неверно предсказать).
Проблема не в cmov/jo а в двух — sub + cmp, когда sub это уже cmp по сути.
то есть да, clang делает хорошо :)

я ступил и смотрел только разные варинты записи для GCC.

А вот компилятор Rust'а предлагает, и в 99% случаев его предложения правильные. Почему? Потому что компилятор ууууумный. А язык правильный.


Последняя Mother of All Errors, которую я словил, добавив в невинную структуру ещё одно поле состояла из ~10 строчек, в которых мне объяснялось, что из-за этого поля (совсем в другом месте, совсем другую структуру) нельзя больше безопасно передавать между тредами. Причём в ошибке мне даже сказали, что можно ещё в одном месте заменить Fn на FnOnce, и тогда будет хорошо. Я сделал — и стало хорошо.

Ну, справедливости ради, многое из того, что проверяет PVS-studio и при этом не завязано на язык (вроде одинаковых веток в условном операторе), сейчас не ловят ни компилятор, ни Clippy, так что есть куда расти.

Рассмотрим ошибку, которую я разбирал в статье

Ошибка лютая, конечно.
Прикольно, но бессмысленно ;). Анализатор убрал код, который с точки зрения языка C++ является лишним.

А если как-то так поставить вопрос, чтобы это служило индикатором некооректной логики?
некооректной
некорректной
Only those users with full accounts are able to leave comments. Log in, please.