2016-02-17 5 views
1

Заявления, подобные int n6 = n1 + ++n1;, являются неопределенным поведением, поскольку они нарушают правила последовательности. Но если они являются нарушением правил последовательности, почему компилятор просто не дает жесткой ошибки? Другие примеры:Почему компилятор не соблюдает правила секвенирования?

i = ++i + i++; // undefined behavior 
i = i++ + 1; // undefined behavior (but i = ++i + 1; is well-defined) 
f(++i, ++i); // undefined behavior 
f(i = -1, i = -1); // undefined behavior 

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

+1

Должен ли компилятор быть в состоянии изобразить [это] (http://coliru.stacked-crooked.com/a/f11297b5b6e064c8)? Это то же самое, но гораздо сложнее диагностировать. – NathanOliver

+0

Жесткая ошибка - это действительный результат неопределенного поведения, поэтому его использование позволяет компиляторам отклонять его, если они могут его обнаружить (например,с «-Werror = sequence-point» или аналогичным) –

+1

@JonathanWakely Жесткая ошибка - это только действительный результат неопределенного поведения в коде, который будет выполняться во время выполнения. '-Werror = sequence-point' может быть очень полезен, но при его использовании GCC больше не соответствует стандарту C++. 'int main() {} void f (int i) {++ i + ++ i; } '- это то, что C вызовет строго соответствующую программу. (Я не уверен, что для него подходит C++). – hvd

ответ

4

Потому что компилятор затрудняет диагностику здесь в общем случае. Вы показали действительно надуманный и очевидный пример, но реальность обычно сложнее, чем эта. Легче сказать: «Не делай этого, и компилятор не должен тебе это объяснять».

+2

Возможно, конкретный пример того, что компилятор не сможет обнаружить, будет хорошим дополнением к вашему ответу, чтобы помочь OP. (Что-то вроде '++ * p + ++ * q' должно делать, когда компилятор не может знать, будет ли' p == q'.) – hvd

+0

Является ли это NP-трудным или неразрешимым или что-то, чтобы обеспечить соблюдение правил последовательности? – djechlin

+0

Комментарий hvd, кажется, противоречит этому ответу. – djechlin

1

-Werror=sequence-point обнаруживает и испускает ошибку компиляции поведения, о котором вы говорите, но в общем случае он создает ложные срабатывания.

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

Я также не знаю, в каком смысле вычислительно сложно проверить правильность последовательности точек (неразрешимый, NP-жесткий и т. Д.). Казалось бы, это повлияло на прежний вопрос.

+0

И когда я прокомментировал вопрос, вызывает отклонение действительных программ. – hvd

+0

@hvd вы ясно знаете об этом больше, чем кто-либо другой по этому вопросу, можете ли вы опубликовать ответ? – djechlin

+0

Я считал это изначально, но чувствовал, что не смог бы добавить много ответа @ PreferenceBean. Я попробую еще раз посмотреть, смогу ли я что-нибудь придумать. – hvd

2

В общем случае очень сложно определить, нарушает ли произвольное выражение правила последовательности.

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++ нет и не может быть никакого правила, чтобы запретить это, компиляторам не разрешается выдавать сообщения об ошибках даже для простых случаев.

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

+0

Да, это. :) –

Смежные вопросы