В общем случае очень сложно определить, нарушает ли произвольное выражение правила последовательности.
int f(int *pa, int *pb) {
return ++*pa + ++*pb;
}
Он может иметь UB по причине, отличной от последовательности, в зависимости от входных значений, например, f(0, 0)
, но если учитывать только последовательность, то это определило поведение?
Недостаточно информации для ответа на этот вопрос. Он нарушает правила последовательности, только если pa == pb
. Там ничего не выйдет, но в равной степени нет ничего, чтобы предположить, что любой код называет его таким.
Если мы не можем сказать, компилятор не может сказать. Поэтому он не может быть плохо сформированным, только неопределенным, и любая диагностика остается как проблема качества реализации.
Тот факт, что он не определен во время выполнения, а не плохо сформирован, имеет другое следствие: это означает, что это только проблема, если код когда-либо выполняется. Я привел пример в комментарии:
int main() { }
void f(int i) { ++i + ++i; }
Функция f
имеет неопределенное поведение, но программа в целом не происходит, потому что функция f
никогда не вызывается. Поскольку в стандарте C++ нет и не может быть никакого правила, чтобы запретить это, компиляторам не разрешается выдавать сообщения об ошибках даже для простых случаев.
Однако компиляторы всегда могут выдавать предупреждение (или любую другую нефатальную диагностику) для любого кода, поэтому полезные компиляторы действительно пытаются обнаружить это и сообщают вам, что вы делаете что-то неправильно.
Должен ли компилятор быть в состоянии изобразить [это] (http://coliru.stacked-crooked.com/a/f11297b5b6e064c8)? Это то же самое, но гораздо сложнее диагностировать. – NathanOliver
Жесткая ошибка - это действительный результат неопределенного поведения, поэтому его использование позволяет компиляторам отклонять его, если они могут его обнаружить (например,с «-Werror = sequence-point» или аналогичным) –
@JonathanWakely Жесткая ошибка - это только действительный результат неопределенного поведения в коде, который будет выполняться во время выполнения. '-Werror = sequence-point' может быть очень полезен, но при его использовании GCC больше не соответствует стандарту C++. 'int main() {} void f (int i) {++ i + ++ i; } '- это то, что C вызовет строго соответствующую программу. (Я не уверен, что для него подходит C++). – hvd