Основное различие между «современными» C и C++ по сравнению с большинством других популярных языков заключается в том, что в то время как другие языки позволяют компиляторам выбирать между различными крайними случаями поведения в Unspecified, авторы стандартов C и C++ не хотели этого делать. ограничить языки платформами, на которых можно легко выполнить любую поведенческую гарантию.
Учитывая конструкцию типа:
int blah(int x)
{
return x+10 > 20 ? x : 0;
}
Java точно определяет поведение для всех значений x, включая те, которые вызывают перенос целых чисел; дизайн ранних компиляторов C для машин с дополнением до двух давал такое же поведение, за исключением того, что машины с разными размерами «int» (16-битные, 36-битные и т. д.) переносились в разных местах. Однако машины, использующие другие представления для целых чисел, могут вести себя иначе.
Кроме того, нередко даже «традиционные» компиляторы C вели себя так, как если бы вычисления выполнялись для более длинного типа. На некоторых машинах было несколько инструкций, которые работали с более длинными типами, и использование этих инструкций и сохранение значений в качестве более длинных типов иногда могло быть дешевле, чем усечение/перенос значений в диапазон «int». На таких машинах неудивительно, что функция, подобная приведенной выше, возвращает x даже для значений, которые находятся в пределах 10 от переполнения. Обратите внимание, что Java пытается свести к минимуму поведенческие различия между реализациями и, таким образом, обычно не допускает даже такого уровня поведенческих вариаций.
Однако современный C делает еще один шаг вперед по сравнению с Java. Это не только допускает возможность того, что компиляторы могут произвольно поддерживать избыточную точность с целочисленными значениями, современный компилятор, получивший функцию, подобную приведенной выше, может сделать вывод, что, поскольку Стандарт позволяет компиляторам делать что угодно, если программа получает входные данные, которые могут вызвать ошибку. если функция получает значение x больше, чем INT_MAX-10, компилятор должен отбросить как нерелевантный любой код, который не будет иметь никакого эффекта, если такие входные данные не будут получены. Конечным результатом этого является то, что целочисленное переполнение может нарушить эффект предшествующего кода произвольным образом.
Таким образом, Java на два шага удалена от модели «неопределенного поведения» современного C; он жестко предписывает гораздо больше вариантов поведения, и даже в тех случаях, когда поведение не является жестко определенным, реализации по-прежнему ограничиваются выбором из различных возможностей. Если не использовать функции из пространства имен Unsafe или не связывать Java с внешними языками, программы на Java будут иметь гораздо более ограниченное поведение, и даже при использовании таких конструкций программы на Java по-прежнему будут подчиняться законам времени и причинно-следственных связей в отличие от программ на C.
person
supercat
schedule
06.10.2016