Секвенирование в сложном условном выражении

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

enum S { };

struct R {
S type, state;
double height;
};

int main ()
{
int rows;
S alive, rc;
double h;
R *r, *n;

// BEGIN
if ( (((r = n-1)   ->type & rc) && h > r->height) ||
(((r = n+1)   ->type & rc) && h > r->height) ||
(((r = n-rows)->type & rc) && h > r->height) ||
(((r = n+rows)->type & rc) && h > r->height) )
{
n->state = alive;
}
// END
}

Однако в рамках проекта с той же компиляцией (clang 3.3 без параметров, кроме пути включения) он дает

warning: multiple unsequenced modifications to 'r' [-Wunsequenced]

(указывая на подвыражение r = n - 1). if заявление (отмечено между BEGIN-END) идентичен в рамках проекта, только типы переменных могут быть разными. Типы, определенные здесь, являются только грубыми приближениями, но я думаю, что они не имеют отношения к предупреждению. Я был в состоянии упростить выражение до

if( (r = n) || (r = n) ) //...

в то же время воспроизводя предупреждение в рамках проекта.

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

Если есть какие-либо идеи относительно формы выражения независимо от типов, это поможет.

РЕДАКТИРОВАТЬ

Используя комментарии Вона Катона, я также обнаружил, что

if( ((r = n-1) ->type) || ((r = n+1) ->type) )

выдает предупреждение, в то время как

if( bool((r = n-1) ->type) || bool((r = n+1) ->type) )

не. S на самом деле это класс, который имитирует перечисление и имеет собственный базовый класс. Перегружены побитовые операторы &, | а также ! для маскировки и неявного преобразования оператора в базовый тип, который в частном случае size_t, Я не знаю, насколько это помогает, но мне жаль, что я не раскрыл более полную информацию с самого начала.

3

Решение

См. N3797 1.9 / 15.

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

5.14 / 2: ( && оператор)
5.15 / 2: ( || оператор)

Если второе выражение оценивается, каждое вычисление значения и связанный побочный эффект
с первым выражением последовательности перед каждым вычислением значения и побочным эффектом, связанным со вторым выражением.

Ссылка на «побочный эффект» означает, что значение r правильно упорядочен.

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

2

Другие решения

Здесь есть общая путаница. Просто так || а также && являются точками последовательности не подразумевает, что среда выполнения оценивает r в том порядке, как вы думаете.

Это может оценить r = n - 1, r = n + 1 и т.п. до любой из if выражения оцениваются в любой заказ это фантазии; то есть не секвенировано

Это то, что предупреждает компилятор.

Кстати, даже языки, которые претендуют на лучшее определение последовательности (например, Java), пострадают от эффекта, на который я обращаю ваше внимание!

1

По вопросам рекламы [email protected]