- 01
- 02
- 03
- 04
- 05
- 06
- 07
- 08
- 09
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
int naive_show_int(int x) {
char buf[32];
char *p = buf + sizeof(buf);
*--p = 0;
int negative = 0;
if (x < 0) {
x = -x;
negative = 1;
}
while (x > 0) {
if (x <= 0)
return -1;
int digit = '0' + x % 10;
if (digit < '0' || digit >= '9')
return -1;
*--p = digit;
x /= 10;
}
if (negative)
*--p = '-';
puts(p);
return 0;
}
bormand 02.02.2016 19:37 # +1
guest 02.02.2016 21:17 # 0
1024-- 02.02.2016 21:25 # 0
Т.е. он в while входит с отрицательным x, затем игнорирует все проверки внутри цикла. Творится сущая хренота.
bormand 02.02.2016 21:45 # 0
P.S. Кстати, деление на 10 он заменил умножением на 1717986919.
1024-- 02.02.2016 21:54 # −1
> Ну и все проверки убирает
А в случае сужения диапазона что творится? Это поддаётся объяснению?
http://ideone.com/DHWxQN
bormand 02.02.2016 22:05 # −1
P.S. А вот про семёрку непонятно, надо дизасм глядеть.
bormand 02.02.2016 22:28 # +1
Короче, в случае с восьмёркой компилятор видит только одно кривое число '9'. С ним он и сравнивает, а потом делает je. Т.е. получается if (digit == '9') return -1.
В случае с семёркой он честно сравнивает с семёркой, но юзает ja, как для unsigned'ов (ведь digit не может быть отрицательным). Т.е. if ((unsigned)digit > 7u) return -1. Но digit у нас отрицательный, т.е. 0xFFFFFчётотам, что явно больше 7. Поэтому и происходит return -1.
Два косяка случайно скомпенсировали друг друга и получилось правильное поведение. UB такой UB.
1024-- 02.02.2016 22:44 # −1
> Но digit у нас отрицательный, т.е. 0xFFFFFчётотам
Однако, новость. Компилятор считает, что т.к. x>0, можно просто от x % 10 откусить один байт и сложить с '0'? А нет, там int же. Компилятор считает, что т.к. x>0, можно просто от x % 10 откусить один байт и сложить с '0' потому, что потом значение используется как char?
bormand 02.02.2016 22:51 # −1
bormand 02.02.2016 21:42 # −1
Там сначала были assert'ы, потом на if'ы поменял, чтобы не докапывались "да у тебя же ассёрты выкокомпилились".
bormand 02.02.2016 21:49 # 0
Elvenfighter 02.02.2016 23:03 # −1
bormand 02.02.2016 23:07 # 0
Хе-хе. А UB то это не убирает (переполнение знакового числа в операторе -), просто заметает под ковёр до поры до времени... Пока в компилятор не добавят новую хитровыебанную оптимизацию, которая понадеется, что старший бит этого unsigned'а всегда будет нулём...
Или там предлагают число кастануть в unsigned, а минус заменить на битовую магию?
bormand 02.02.2016 23:30 # 0
Ололо, она таки есть! http://ideone.com/oFheOh
Т.е. (unsigned)(-x) тоже неплохо стреляет в колено...
Т.е. остаётся только сначала кастовать в unsigned (благо, емнип, это стандарту не противоречит и вполне документировано) и в нём уже делать отрицание.
bormand 02.02.2016 23:41 # 0
Shifts: 00000080 00000040 00000020 00000010 00000008 00000004 00000002 00000000
j123123 03.02.2016 00:11 # +2
prog.c:9:17: runtime error: negation of -2147483648 cannot be represented in type 'int'; cast to an unsigned type to negate this value to itself
Да и в новых GCC этот -fsanitize=undefined вроде как появился
1024-- 02.02.2016 19:57 # 0
bormand 02.02.2016 20:03 # +3
guest 02.02.2016 21:13 # −6
Elvenfighter 02.02.2016 21:25 # +2
> return -1;
А за что так с девяткой?
1024-- 02.02.2016 21:39 # 0
Но взгляните сюда: http://ideone.com/DHWxQN (разные ограничения на digit)
Какой эффект!
bormand 02.02.2016 21:41 # −1
3_dar 02.02.2016 22:27 # −1
bormand 02.02.2016 22:57 # −1
Цитата из стандарта нужна?
3_dar 02.02.2016 23:13 # −1
0x80000000 разве int? Тогда уж -0x80000000
bormand 02.02.2016 23:16 # 0
Да, правильное замечание.
3_dar 02.02.2016 23:25 # +1
Elvenfighter 02.02.2016 22:59 # −1
> int x;
> x = -x;
Спойлер: http://www.cplusplus.com/reference/climits/
bot 02.02.2016 22:57 # −1
j123123 03.02.2016 00:17 # +4
Где здесь C++, bormand?!
j123123 04.02.2016 12:13 # +4
http://goo.gl/0K4VFR - c оптимизацией в GCC получаем бесконечный цикл. Без оптимизации (или с оптимизацией -O1) возвращает -2147483648
Soul_re@ver 04.02.2016 14:05 # +6
Вот ещё пример конечного/бесконечного цикла в зависимости от оптимизаций. Пикантности прибавляет факт, что условие цикла не зависит от UB. Но, наличие UB не гарантирует работу даже частей программы до него.
yet_another_one_shit 03.05.2018 14:25 # 0
> x /= 10;
Простите мне мою пупость. Вы што, ожидали получить отрицателное число при делении 2 положительных???
или я что-то проглядел?
yet_another_one_shit 03.05.2018 14:31 # 0
???????????????????
ЗЫ. переполнение?
gost 03.05.2018 14:53 # +1
bormand 03.05.2018 14:59 # +1
Хех, не научились они пока доказывать инварианты по индукции. Вот и не выбросило проверки. С while (x > 0) инвариант цикла более явный, там выбрасывает "невыполнимые" ветки.
yet_another_one_shit 03.05.2018 14:34 # +1