Является ли поведение компилятора undefined, с Undefined Поведением?
Когда я ответил на этот question, я написал:
Во-первых, важно отметить, что не только поведение пользовательской программы undefined, но и поведение компилятора undefined.
Но в комментарии было , поэтому я хочу задать здесь вопрос:
Если исходный код содержит Undefined Поведение, является ли это только поведение переведенного машинного кода undefined или поведение компилятора undefined тоже?
Стандарт определяет поведение абстрактной машины (1.9):
Семантические описания в этом международном стандарте определяют параметризованную недетерминированную абстрактную машина. В этом Международном стандарте нет требований к структуре соответствующих реализаций. В частности, им не нужно копировать или эмулировать структуру абстрактной машины. Скорее, соответствующие реализации требуется, чтобы эмулировать (только) наблюдаемое поведение абстрактной машины, как объяснено ниже.
Может быть, вопрос в том, что компилятор является частью этой машины, и если да, если этой части разрешено вести себя с помощью Undefined?
Более практическая версия этого вопроса будет:
Предположим, что компилятор сбой или не выдаст какой-либо вывод, когда он найдет UB на всех путях управления, например, в этой программе:
int main() {
complex_things_without_UB();
int x = 42;
x = x++; //UB here
return x;
}
но в противном случае он всегда будет создавать корректные двоичные файлы. Будет ли это все еще стандартным компилятором?
Ответы
Ответ 1
Стандарт С++ определяет поведение для кода, он не определяет поведение для компилятора. Таким образом, на самом деле не имеет смысла ссылаться на поведение undefined компилятора - он никогда не был четко определен для начала. Единственное требование состоит в том, что он создает реализацию, которая соответствует стандартным правилам для кода. Как это происходит, это детализация реализации.
Ответ 2
Это довольно размытая линия в целом. Дело в том, что исходный код не имеет определенного поведения, что означает, что поведение сгенерированного кода недостаточно четко определено.
Компилятор должен по всем учетным записям вести себя определенным образом - но, конечно, это может быть скорее "случайным" (например, компилятор может выбрать случайное число в свой расчет - или даже вызов rand
- и он по-прежнему прекрасно соответствует правам компилятора). Есть, конечно, случаи, когда компилятор (ab) использует тот факт, что он что-то знает undefined, чтобы сделать оптимизацию.
Я считаю это очень плохой реализацией компилятора, если, например, компилятор сработает или приведет к форматированию жесткого диска, но я считаю, что компилятор может быть "прав", если он говорит "Это undefined, я отказываюсь компилировать его" [в некотором роде].
Конечно, есть (довольно много) ситуаций, когда что-то есть undefined, а не потому, что сама конструкция undefined, а потому, что "трудно определить одно поведение, которое можно реализовать во многих местах" - например, использование недопустимого указателя (int* p = (int*) rand();
или use-after-free) - это undefined, но компилятор может не знать и понимать, правильно ли он или нет. Вместо этого до архитектуры процессора происходит то, что происходит, если вы используете указатель на случайном адресе или после его освобождения. Оба случая могут привести к сбою на одной машине, а не к сбою, но ошибочному результату по другому, а в некоторых случаях "вы не заметите, что что-то не так". Это явно не поведение компилятора undefined, а результирующая программа.
Ответ 3
это только поведение переведенного машинного кода undefined, или это поведение компилятора undefined тоже?
ISO C и С++ описывают, как выглядят программы на C и С++. Они не описывают среду, в которой они работают. Обычно мы используем термин компилятор для ссылки на инструмент, который переводит C и С++ в машинный код; формально, однако, используемый термин является реализацией, которая определенно шире.
Следовательно, единственное поведение, которое является undefined, является одним из программ. Это также дается определением UB:
undefined поведение
поведение при использовании непереносимого или ошибочного программа или ошибочные данные, для которых этот Международный Стандарт не предъявляет требований
Ответ 4
Если код имеет undefined поведение, это означает, что стандарты не знают, как обращаться с такой вещью. Таким образом, он может выдавать любой результат. Я думаю, что это не связано с компилятором, поскольку это не имеет смысла. Имеет смысл, что это должна быть реализация, которая работает в соответствии со стандартами.
Итак, если стандарты не знают, как обрабатывать такой код, то как компиляторы могут дать определенный результат?
Ответ 5
Предполагая, что "поведение undefined для компилятора" означает "нет требований к поведению создаваемой исполняемой программы", тогда поведение компилятора undefined при представлении исходного кода, содержащего конструкторы поведения undefined,
Сравните это с поведением компилятора с правильным исходным кодом. Все компиляторы, придерживающиеся стандарта, должны создавать исполняемый код с эквивалентным поведением, тот, который определен стандартом для правильного исходного кода.
Ответ 6
Мое собственное мнение состоит в том, что поведение в "undefined поведение" - это поведение. Спецификация относится к процессу "перевода", который мы можем приравнивать к компиляции, но тот факт, что вы можете скомпилировать программу для исполняемого кода, здесь не уместен, результат по-прежнему считается частью реализации, по крайней мере, в качестве как поведение. Обратите внимание, что в то время как спецификация определяет, как будет вести себя программа на C, когда она устанавливает требования к реализации, а поведение программы также может считаться требованием (или набором требований) к реализации.
В любом случае поведение undefined может, безусловно, ссылаться на поведение компилятора. См. Примечание в C11 3.4.3:
Возможное поведение undefined варьируется от полного игнорирования ситуации с непредсказуемыми результатами, ведения во время перевода или выполнения программы документированным образом, характерным для среды (с выдачей диагностического сообщения или без него), до прекращения перевода или выполнение (с выдачей диагностического сообщения).
"Прекращение перевода" явно относится к сбою компиляции, тогда как "завершение выполнения..." явно относится к поведению запущенной программы.
См. также Приложение J.2, в котором перечислены примеры поведения undefined. Среди примеров:
Непустой исходный файл не заканчивается символом новой строки, которому не сразу предшествует символ обратной косой черты или заканчивается частичным маркером предварительной обработки или комментарием (5.1.1.2)
Кажется смешным, что это должно вызывать поведение undefined во время выполнения, а не во время перевода. Существуют и другие подобные примеры. Весь набор четко показывает случаи, когда поведение undefined может происходить как во время компиляции, так и во время выполнения.
Ответ 7
В стандарте нет компилятора, и детали реализации зависят от поставщиков.
В стандарте определяется , как должен выглядеть код (в синтаксическом и семантическом смысле) и/или быть ограниченным в терминах сложности относительно некоторых стандартных библиотечных алгоритмов. Исходный код не должен иметь точного поведения (и это нигде не определено). Каждый компилятор просто должен создать код, который в правиле as-if будет правильным.
Не имеет смысла ссылаться на поведение undefined компилятора