Подтвердить что ты не робот

Является ли поведение программы, имеющей поведение undefined на недостижимом пути?

Рассмотрим

void swap(int* a, int* b)
{
    if (a != b){
        *a = *a ^ *b;
        *b = *a ^ *b;
        *a = *a ^ *b;
    }   
}

int main()
{
    int a = 0;
    int b = 1;
    swap(&a, &b); // after this b is 0 and a is 1
    return a > b ? 0 : a / b;
}

swap - попытка обмануть компилятор, чтобы не оптимизировать программу.

Определено ли поведение этой программы? a / b никогда не достижим, но если бы это было тогда, вы получили бы деление на ноль.

4b9b3361

Ответ 1

Нет необходимости основывать позицию на этом вопросе на полезности любой заданной конструкции или практики кода или ни о чем написанном о С++, будь то в его стандарте или в другом SO-ответе, независимо от того, как могут быть аналогичные определения С++, Ключевым моментом, который следует учитывать, является определение C undefined для C:

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

(C2011, 3.4.3/1, добавлено выделение)

Таким образом, поведение undefined запускается временно ( "при ​​использовании" конструкции или данных), а не простое присутствие. * Удобно, что это согласовано для поведения undefined от данных и данных, возникающих из программных конструкций; стандарт не обязательно был там согласован. И, как описывает другой ответ, это определение "по использованию" является хорошим выбором дизайна, поскольку оно позволяет программам избегать выполнения поведения undefined, связанных с ошибочными данными.

С другой стороны, если программа выполняет поведение undefined, то из стандартного определения следует, что все поведение программы undefined. Эта обусловленная неопределенность является более общим видом, возникающим из-за того, что UB, связанный непосредственно с ошибочными данными или конструкцией, в принципе может включать изменение поведения других частей программы, даже ретроактивно (или, по-видимому, так). Конечно, существуют дополнительные языковые ограничения на то, что может произойти - так что нет, носовые демоны на самом деле не будут появляться, но они не обязательно настолько сильны, как можно было бы предположить.


* Предостережение: во время перевода используются некоторые программные конструкции. Они производят UB в переводе программы, в результате чего каждое выполнение программы имеет полное поведение undefined. Для несколько глупого примера, если ваш источник программы не заканчивается невыбранной новой строкой, то поведение программы полностью undefined (см. C2011, 5.1.1.2/1, пункт 2).

Ответ 2

Поведение выражения, которое не оценивается, не имеет отношения к поведению программы. Поведение, которое было бы undefined, если бы выражение оценивалось, не влияет на поведение программы.

Если бы это было так, то этот код был бы бесполезен:

if (p != NULL)
    …; // Use pointer p.

(Ваши XOR могут иметь поведение undefined, так как они могут создавать ловушечное представление. Вы можете победить оптимизацию для таких академических примеров, как это, объявив объект изменчивым. Если объект изменчив, реализация C не может знать, его значение может измениться из-за внешних средств, поэтому каждое использование объекта требует, чтобы реализация считывала его значение.)

Ответ 3

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

extern struct foo z;

int main(int argc, char **argv)
{
    if (argc > 2) z;
    return 0;
}

Посредством моего чтения Стандарта он явно характеризует преобразования lvalue на неполных типах как вызывающие Undefined Поведение (среди прочего, неясно, какая реализация может генерировать код для такой вещи), поэтому Стандарт не будет налагать никаких требований при поведении, если argc равно 3 или более. Я не могу идентифицировать какое-либо ограничение в Стандарте, которое нарушает вышеуказанный код, и ни одна причина поведения не должна быть полностью определена, если argc равно 2 или меньше. Тем не менее, многие компиляторы, включая gcc и clang, полностью отвергают вышеуказанный код.