Неопределенное деление на 0 undefined поведение?

У меня возникли разногласия с некоторыми сотрудниками по следующему коду:

int foo ( int a, int b )
{
    return b > 0 ? a / b : a;
}

Этот код демонстрирует поведение undefined?

EDIT: несогласие началось с того, что кажется ошибкой в ​​чрезмерно нетерпеливом компиляторе оптимизации, где была проверена проверка b > 0.

Ответ 1

Нет.


Цитаты из N4140:

§5.16 [expr.cond]/1

Условные выражения группы справа налево. Первое выражение контекстно преобразованный в bool. Он оценивается, и если это так, результатом условного выражения является значение второго выражение, в отличие от третьего выражения. Только один из второе и третье выражения оцениваются.

Далее:

§5 [expr]/4

Если во время оценки выражения результат не математически определены или нет в диапазоне представимых значений для его тип, поведение undefined.

Это явно не происходит здесь. В том же пункте упоминается деление на ноль явно в примечании и, хотя оно ненормативно, делает его еще более ясным, что его отношение к этой ситуации:

[Примечание: большинство существующих реализаций С++ игнорируют целочисленные переполнения. Обработка деления на ноль, формирование остатка с использованием нуля делитель, и все исключения с плавающей запятой различаются между машинами и обычно настраивается библиотечной функцией. -end note]


Существуют также косвенные доказательства, усиливающие приведенную выше точку: условный оператор используется для условного поведения undefined.

§8.5 [dcl.init]/12.3

int f(bool b) {
  unsigned char c;
  unsigned char d = c; // OK, d has an indeterminate value
  int e = d; // undefined behavior
  return b ? d : 0; // undefined behavior if b is true
}

В приведенном выше примере использование d для инициализации int (или ничего, кроме unsigned char) - undefined. Тем не менее ясно, что UB встречается только в том случае, если оценивается ветвь UB.


Исходя из перспективы языка-юриста: если это может быть UB, то любое деление можно рассматривать как UB, так как делитель может быть равен 0. Это не дух правила.

Ответ 2

В примере кода нет способа деления на ноль. Когда процессор выполняет a / b, он уже проверял, что b > 0, поэтому b отличен от нуля.

Следует отметить, что если a == INT_MIN и b == -1, то a/b также является undefined. Но это все равно предотвращается, потому что в этом случае условие оценивается false.

Хотя я не уверен, что вы имели в виду return b != 0 ? a / b : a;, а не return b > 0 ? a / b : a;. Если b меньше нуля, деление остается действительным, если только это условие не описано выше.

Ответ 3

Этот код демонстрирует поведение undefined?

Нет. Это не так. Выражение

return b > 0 ? a / b : a;  

эквивалентно

if(b > 0)
    return a/b;     // this will be executed only when b is greater than 0
else
    return a;  

Разделение выполняется только тогда, когда b больше, чем 0.

Ответ 4

Если бы это был UB, значит,

if(a != null && *a == 42)
{
 .....
}

И последовательность ifs, ands и ors четко разработана, чтобы специально разрешить этот тип конструкции. Я не могу представить, что ваши коллеги будут спорить с этим.