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
, Я не знаю, насколько это помогает, но мне жаль, что я не раскрыл более полную информацию с самого начала.
См. N3797 1.9 / 15.
За исключением отмеченных случаев, оценки операндов отдельных операторов и подвыражений отдельных выражений не являются последовательными.
5.14 / 2: ( &&
оператор)
5.15 / 2: ( ||
оператор)
Если второе выражение оценивается, каждое вычисление значения и связанный побочный эффект
с первым выражением последовательности перед каждым вычислением значения и побочным эффектом, связанным со вторым выражением.
Ссылка на «побочный эффект» означает, что значение r
правильно упорядочен.
Я читаю, что это предупреждение будет неверным. Выражение правильно упорядочено (исключая любые странные эффекты из кода, не показанного здесь).
Здесь есть общая путаница. Просто так ||
а также &&
являются точками последовательности не подразумевает, что среда выполнения оценивает r
в том порядке, как вы думаете.
Это может оценить r = n - 1
, r = n + 1
и т.п. до любой из if
выражения оцениваются в любой заказ это фантазии; то есть не секвенировано
Это то, что предупреждает компилятор.
Кстати, даже языки, которые претендуют на лучшее определение последовательности (например, Java), пострадают от эффекта, на который я обращаю ваше внимание!