Взгляните на этот фрагмент кода
int main()
{
int i = 1U << 31; // assume this yields INT_MIN
volatile int x;
x = -1;
x = i / x; //dividing INT_MIN by -1 is UB
return 0;
}
Он вызывает неопределенное поведение на типичной платформе, но «поведение» сильно отличается от того, что я ожидаю — оно действует так, как если бы это был бесконечный цикл. Я могу придумать сцену, которую он кусает.
Конечно, undefined есть undefined, но я проверил выходную сборку, она использует простую idiv
-- почему она не перехватывает? Для сравнения, деление на ноль вызывает немедленное прерывание.
Использование Windows 7 64 бит и MingW64
Кто-нибудь может мне это объяснить?
ИЗМЕНИТЬ
Я пробовал несколько вариантов, и результаты всегда были одинаковыми.
Вот сборка:
.file "a.c"
.def __main; .scl 2; .type 32; .endef
.section .text.startup,"x"
.p2align 4,,15
.globl main
.def main; .scl 2; .type 32; .endef
.seh_proc main
main:
subq $56, %rsp
.seh_stackalloc 56
.seh_endprologue
call __main
movl $-1, 44(%rsp)
movl $-2147483648, %eax
movl 44(%rsp), %ecx
cltd
idivl %ecx
movl %eax, 44(%rsp)
xorl %eax, %eax
addq $56, %rsp
ret
.seh_endproc
.ident "GCC: (x86_64-posix-sjlj, built by strawberryperl.com project) 4.8.2"
INT_MIN
на-1
, он попал в ловушку с «исключением с плавающей запятой», таким же, как если бы я разделил на ноль (но это было в Mac OS X). - person Pascal Cuoq   schedule 18.08.2014INT_MIN
на-1
— это неопределенное поведение. Это вовсе не особый случай: это обычное арифметическое переполнение со знаком. Но на x86 инструкция обычно вызывает аппаратное исключение, а не зацикливается. (Обратите внимание, что в C11INT_MIN % -1
тоже было преобразовано в UB, несмотря на то, что это не случай арифметического переполнения). - person Pascal Cuoq   schedule 18.08.2014x
volatile
? Это актуально? - person Fiddling Bits   schedule 18.08.2014idiv
, будут медленными, относительная стоимость ограничения поведения должна быть небольшой, вне зависимости от того, предписывает ли Стандарт такие ограничения или нет. - person supercat   schedule 16.07.2018