# V2661. MISRA. A 'for' loop should be well-formed.

Диагностическое правило основано на руководстве MISRA (Motor Industry Software Reliability Association) по разработке программного обеспечения.

Правило актуально только для языка C.

Цикл `for` должен быть отформатирован в соответствии со следующими правилами:

Первый оператор цикла (`Init-statement`) должен:

- либо быть пустым;
- либо не иметь постоянных побочных эффектов;
- либо определять и инициализировать счётчик цикла.

Второй оператор (`Condition`) должен:

- не иметь постоянных побочных эффектов;
- использовать счётчик или его же совместно с флагом управления циклом;
- не использовать объекты, которые модифицируются в теле цикла.

Третий оператор цикла (`Expression`) должен:

- не иметь постоянных побочных эффектов, кроме модификации счетчика цикла;
- не использовать объекты, которые модифицируются в теле цикла.

Соблюдение правил оформления циклов `for` снижает вероятность ошибок, а также упрощает процесс отладки и обзора кода. Такой подход позволяет сразу видеть всю логику работы цикла в его заголовке, исключая непредсказуемое поведение.

Примечание. Допустимо использовать цикл с тремя пустыми операторами `for( ; ; )`.

Рассмотрим пример некорректного кода:

    for (size_t i = 0;
         i < users.size() && retry_count < MAX_RETRIES; // <=
         i += (retry_count > 0 ? 0 : 1))                // <=
    {
      if (!checkUser(users[i]))
      {
        retry_count += 1;        // <=
      }
      else
      {
        retry_count = 0;         // <=
      }
      // ....
    }

Опасность кода заключается в неочевидном зависании цикла на проблемном пользователе. Если функция `checkUser` постоянно возвращает `false` при обработке какого-то пользователя, цикл застревает на одной позиции, пока не исчерпает все попытки. Это приводит к пропуску всех последующих пользователей, что бывает сложно обнаружить при обзоре кода.

В данном случае правильное форматирование запрещает использование `retry_count` во втором и третьем операторе цикла `for`, поскольку эта переменная модифицируется в теле цикла. Чтобы исправить проблему, можно вынести механизм валидации в отдельную функцию. Тогда цикл будет работать предсказуемо и обрабатывать всех пользователей.

Исправленный код:

    bool checkUserWithRetry(const std::string& user) {
        for (int attempt = 0; attempt < MAX_RETRIES; attempt++) {
            if (checkUser(user)) return true;
        }
        return false;
    }
    // ....
    for (size_t i = 0; i < users.size(); i++) {
        if (!checkUserWithRetry(users[i])) {
            logError("Failed to process user: " + users[i]);
        }
    }
    // ....

Данная диагностика классифицируется как:

MISRA-C-2023-14.2