Подтвердить что ты не робот

Будучи уверенным в "неизвестном порядке оценки"

Начиная с версии 1.80, Cppcheck сообщает мне, что

Выражение 'msg [ipos ++] = контрольная сумма (& msg [1], ipos-1)' зависит от порядка оценки побочных эффектов

в этой кодовой последовательности (упрощенный, data - переменная)

BYTE msg[MAX_MSG_SIZE];  // msg can be smaller, depending on data encoded
int ipos = 0;
msg[ipos++] = MSG_START;
ipos += encode(&msg[ipos], data);
msg[ipos++] = checksum(&msg[1], ipos-1);  // <---- Undefined Behaviour?
msg[ipos++] = MSG_END;   // increment ipos to the actual size of msg

и рассматривает это как ошибку, а не проблему переносимости.

Код C (включен в проект с преобладанием С++), скомпилированный с компилятором, совместимым с С++ 98, и тем временем работает, как и ожидалось, в течение десятилетий. Cppcheck запускается с С++ 03, C89, автоматически обнаруживает язык.

Я признаюсь, что код лучше переписывать. Но прежде чем это сделать, я пытаюсь понять: действительно ли это зависит от порядка оценки? Как я понимаю, правый операнд сначала оценивается (он должен быть до вызова), затем выполняется назначение (до msg[ipos]) с приращением ipos, выполненным последним.

Я ошибаюсь в этом предположении, или это просто ложный позитив?

4b9b3361

Ответ 1

Этот код действительно зависит от порядка оценки таким образом, который не определен:

msg[ipos++] = checksum(&msg[1], ipos-1);

В частности, не указано, будет ли ipos++ увеличиваться до или после ipos-1. Это связано с тем, что в = нет < точки последовательности", только в конце полного выражения (;).

Вызов функции - это точка последовательности. Но это гарантирует только, что ipos-1 происходит до вызова функции. Это не гарантирует, что ipos++ произойдет после.

Кажется, код должен быть переписан следующим образом:

msg[ipos] = checksum(&msg[1], ipos-1);
ipos++; // or ++ipos

Ответ 2

Порядок оценки операндов = не указан. Итак, для начала, код зависит от неуказанного поведения.

Что еще хуже, так это то, что ipos используется дважды в одном и том же выражении без точки последовательности между ними, для несвязанных целей, что приводит к поведению undefined.

C99 6.5

Между предыдущей и следующей точками последовательности объект должен иметь измененное значение хранимого значения не более одного раза путем оценки выражения. Кроме того, предыдущее значение должно быть считано только для определения сохраняемого значения.

Тот же текст относится к C90, C99, С++ 98 и С++ 03. В C11 и С++ 11 формулировка изменилась, но смысл одинаков. Это поведение undefined, pre-С++ 11.

Компилятор не должен давать диагностику для поведения undefined. Тебе повезло, что так оно и было. Это не является ложным положительным - ваш код содержит серьезную ошибку, полностью от исходного кода C.