Есть ли у Java неопределенное поведение, как у C++?

Неопределенное поведение и точки последовательности

Ссылка выше говорит о точке следования и побочном эффекте в C++.

Одним словом, это означает, что между двумя точками последовательности, если у нас есть более одного побочного эффекта, порядок побочных эффектов не указан.

Например,

int x = 1;
int y = 2;
int z = x++ + y++;

В чем мы можем быть уверены, так это в том, что z равно 3. После того, как z получит 3, x и y увеличатся --- есть два побочных эффекта, поэтому мы не знаем, какой из них увеличивается первым.

Кроме того, в приведенной выше ссылке перечислены все виды точек последовательности.

Мой вопрос: у Java точно такой же случай? Я имею в виду те же точки следования и то же неопределенное поведение?


person Yves    schedule 06.10.2016    source источник
comment
Есть ли у Java даже неопределенное поведение? Связано: programmers.stackexchange.com/q/153843/144548   -  person vsoftco    schedule 06.10.2016
comment
Нет, точки последовательности, или последовательность, уникальны для C++. Однако у Java есть свои виды неопределенного поведения.   -  person Sam Varshavchik    schedule 06.10.2016


Ответы (3)


Основное различие между «современными» 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

Если он не указан, то он не определен и у вас нет никаких гарантий.

Java — это язык, и поэтому существует спецификация: так называемая JLS (спецификация языка Java).

Если что-то не указано (например, порядок значений HashMap), вы не можете ожидать сохранения порядка. В этом случае JLS похож на Javadocs.

Соответственно, если что-то указано, но поведение неверно, то это ошибка.

Ваш случай указан в JLS, раздел 15.18 Аддитивные операторы.

person Grim    schedule 06.10.2016

Результаты оценки выражений в одном потоке полностью указаны в спецификации языка Java. При вычислении выражений (в одном потоке) поведение undefined отсутствует.

В C/C++ «неопределенное поведение» означает, что может произойти что угодно. Если вы поместите int z = x++ + y++; в свою программу на C, компилятор может решить сгенерировать код, который форматирует ваш жесткий диск, и он все равно будет соответствовать стандарту. В Java тоже ничего подобного нет.

Поведение некоторых конструкций в многопоточном приложении может быть недетерминированным (если они не синхронизированы должным образом), но и не полностью неопределенным — ясно, что (из множества вещей) может произойти, если вы этого не сделаете. правильно синхронизировать приложение - но вы не знаете, что из списка происходит.

И есть некоторые Java API, которые не определяют свой результат, если вы не вызываете их определенным образом. Их поведение может варьироваться от версии к версии в библиотеке, но обычно поведение одинаково в одной и той же версии.

person Erwin Bolwidt    schedule 06.10.2016