Неопределенные точки поведения и последовательности
Ссылка выше говорит о точке последовательности и побочном эффекте в C ++.
Одним словом, это означает, что между двумя точками последовательности, если у нас более одного побочного эффекта, порядок побочных эффектов не определен.
Например,
int x = 1;
int y = 2;
int z = x++ + y++;
Мы можем быть уверены, что z
равно 3. После z
получая 3, x
а также y
будет увеличиваться — есть два побочных эффекта, поэтому мы не знаем, какой из них увеличивается первым.
Кроме того, ссылка выше перечислила все виды точек последовательности.
Мой вопрос: у Java точно такой же случай? Я имею в виду те же самые точки последовательности и то же неопределенное поведение?
Основное различие между «современными» C и C ++ по сравнению с большинством других популярных языков заключается в том, что, хотя другие языки позволяют компиляторам выбирать между различными вариантами поведения в неуказанном порядке, авторы стандартов C и C ++ не хотели ограничить языки до платформ, где легко можно было бы обеспечить любые виды поведенческих гарантий.
Учитывая конструкцию, как:
int blah(int x)
{
return x+10 > 20 ? x : 0;
}
Java точно определяет поведение для всех значений x, в том числе
что приведет к целочисленному переносу; дизайн ранних компиляторов C для
машины с двумя комплементами будут иметь такое же поведение, за исключением того, что машины
с разными размерами «int» (16 бит, 36 бит и т. д.) будет переноситься на разные
мест. Машины, которые используют другие представления для целых чисел, могут вести себя
иначе, однако.
Кроме того, это не было бы необычным даже для «традиционных» компиляторов C
вести себя так, как будто вычисления были выполнены на более длинном типе. Немного
машины имели несколько инструкций, которые работали с более длинными типами, и используя
эти инструкции и сохраняя значения как более длинные типы иногда могут быть
дешевле, чем усечение / перенос значений в диапазон «int». На такие
машины, это не было бы удивительно для функции, как выше, чтобы дать
х даже для значений, которые были в пределах 10 от переполнения. Обратите внимание, что Java пытается
минимизировать поведенческие различия между реализациями, и, следовательно, не
как правило, позволяют даже этот уровень поведенческих изменений.
Современный C, однако, выходит за рамки Java. Мало того, что это позволяет
за возможность того, что компиляторы могут произвольно сохранять избыточную точность
с целочисленными значениями современный компилятор, которому дана функция, подобная приведенной выше, может
сделать вывод, что, поскольку стандарт позволит компиляторам делать что угодно
если программа получает входные данные, которые заставили бы функцию получить значение
х больше INT_MAX-10, компилятор должен отбросить как неактуальный любой код
что не будет иметь никакого эффекта, если такие входные данные не будут получены. Чистый эффект
это то, что целочисленное переполнение может нарушить эффект предшествующий код
в произвольном порядке.
Таким образом, Java на два шага удалена от модели «неопределенного поведения» Modern C;
он жестко предписывает гораздо больше поведения, и даже в тех случаях, когда поведение не жестко определенные реализации по-прежнему ограничены выбором из различных возможностей. Если кто-либо не использует функции в пространстве имен Unsafe или не связывает Java с внешними языками, Java-программы будут иметь гораздо более ограниченное поведение, и даже при использовании таких конструкций Java-программы будут по-прежнему подчиняться законам времени и причинности так, как не могут C-программы.
Если он не указан, то он не определен и у вас нет никаких гарантий.
Java — это язык, и поэтому существует спецификация: так называемая JLS (спецификация языка Java).
Если что-то не указано (например, порядок значений HashMap), вы не можете ожидать сохранения порядка. JLS в этом случае похож на Javadocs.
Соответственно, если что-то является указано, но поведение не так, то это ошибка.
Ваш случай указано в JLS, раздел 15.18 Аддитивные операторы.
Результаты оценки выражений для одного потока полностью указаны в спецификации языка Java. В оценке выражений нет неопределенного поведения (в одном потоке).
В C / C ++ «неопределенное поведение» означает, что может произойти все что угодно. Если вы положите int z = x++ + y++;
в вашей C-программе компилятор может решить сгенерировать код, который форматирует ваш жесткий диск, и он все равно будет соответствовать стандарту. Ничего подобного в Java тоже нет.
Поведение некоторых конструкций в многопоточном приложении может быть недетерминированным (если не правильно синхронизировано), но оно также не является полностью неопределенным — ясно, что (из ряда вещей) может произойти, если вы этого не сделаете правильно синхронизировать приложение — но вы не знаете, какие вещи из списка происходят.
И есть некоторые API Java, которые не определяют их результат, если вы не вызываете их определенным указанным способом. Их поведение может варьироваться от версии к версии библиотеки, но обычно поведение совпадает в пределах одной и той же версии.