В случае флага переполнения может показаться, что доступ к этому флагу был бы большим благом для кросс-архитектурного программирования. Это обеспечило бы безопасную альтернативу использованию неопределенного поведения для проверки целочисленного переполнения со знаком, такого как:
if(a < a + 100) //detect overflow
Я понимаю, что есть безопасные альтернативы, такие как:
if(a > (INT_MAX - 100)) //detected overflow
Однако может показаться, что доступ к регистру состояния или отдельным флагам в нем отсутствует как в языках C, так и в C ++. Почему эта функция не была включена или какие языковые решения были приняты, чтобы запретить эту функцию?
Пример для последнего:
int x = 7;
x += z;
int y = 2;
y += z;
Оптимизатор может преобразовать это в этот псевдо-ассемблерный код:
alloc_stack_frame 2*sizeof(int)
load_int 7, $0
load_int 2, $1
add z, $0
add z, $1
который в свою очередь будет больше похож на
int x = 7;
int y = 2;
x += z;
y += z;
Теперь, если вы запрашиваете регистры между
int x = 7;
x += z;
if (check_overflow($0)) {...}
int y = 2;
y += z;
затем, после оптимизации и разборки вас может быть конец с этим:
int x = 7;
int y = 2;
x += z;
y += z;
if (check_overflow($0)) {...}
что тогда неверно.
Можно создать больше примеров, например, что происходит с переполнением при постоянном сворачивании-компиляции.
Sidenotes: Я помню старый компилятор Borland C ++ с небольшим API для чтения текущих регистров процессора. Однако приведенная выше аргументация об оптимизации все еще применима.
На другом знаке: для проверки на переполнение:
// desired expression: int z = x + y
would_overflow = x > MAX-y;
более конкретный
auto would_overflow = x > std::numeric_limits<int>::max()-y;
или лучше, менее конкретно:
auto would_overflow = x > std::numeric_limits<decltype(x+y)>::max()-y;
Потому что C и C ++ разработаны, чтобы быть независимыми от платформы. Статус в реестре нет.
В наши дни для реализации целочисленной арифметики со знаком используется универсальное дополнение «два», но так было не всегда. Его дополнение или знак и абсолютное значение были довольно распространенным явлением. И когда C был впервые разработан, такие процессоры все еще были в общем пользовании. Например. COBOL различает отрицательный и положительный 0, которые существовали на этих архитектурах. Очевидно, что поведение переполнения на этих архитектурах совершенно иное!
Кстати, вы не может полагаться на неопределенное поведение для обнаружения переполнения, потому что разумные компиляторы увидев
if(a < a + 100)
напишет предупреждение и скомпилирует
if(true)
… (при условии, что оптимизации включены, а конкретная оптимизация не отключена).
И обратите внимание, что вы не можете положиться на предупреждение. Компилятор выдаст предупреждение только когда условие закончится true
или же false
после эквивалентных преобразований, но есть много случаев, когда условие будет изменено при наличии переполнения, не заканчивая как простой true
/false
,
Я могу думать о следующих причинах.
Предоставляя доступ к флагам регистрации, переносимость языка между платформами жестко ограничена.
Оптимизатор может радикально изменить выражения и сделать ваши флаги бесполезными.
Это сделало бы язык более сложным
Большинство компиляторов имеют большой набор встроенных функций для выполнения наиболее распространенных операций (например, сложение с переносом) без использования флагов.
Большинство выражений можно переписать безопасным способом, чтобы избежать переполнения.
Вы всегда можете вернуться к встроенной сборке, если у вас есть очень специфические потребности
Доступ к регистрам статуса кажется недостаточно необходимым, чтобы пройти процесс стандартизации.