Когда Cppcheck запускает этот код,[1] это жалуется на ошибка:
void bool_express(bool aPre, bool aX, bool aPost)
{
bool x;
const bool pre = aPre;
if (pre) {
x = aX;
}
const bool post = aPost;
// error checking passage of the original code:
if ( !pre || !x || !post ) {
if ( !pre ) {
trace("pre failed");
} else if ( !x ) { // <-- HERE Cppcheck complains
trace("x failed");
} else {
trace("post failed");
}
} else {
// success passage of the original code:
trace("ok");
}
}
Это сообщение, которое заставляет меня нервничать:
Id: uninitvar
Summary: Uninitialized variable: x
Message: Uninitialized variable: x
Я думаю, что это ложный позитив, но я признаю, что это не может быть очевидным. Тем не менее я не хочу трогать этот код, потому что он старый и намного тяжелее, чем эта извлеченная версия.
Вы когда-нибудь сталкивались с подобными ситуациями? Как с этим бороться?
[1] Этот код сводится к его костям, исходный код устанавливает предварительное условие (pre
) что-то делает (x
), то форсирует постусловие (post
), после этого проверяются некоторые условия ошибки. Я преобразовал результаты выполнения функций, которые вызываются и затем сохраняются в pre
, x
, а также post
в 3 аргумента моего теста.
Это ложно положительный в Cppcheck. я решена это путем добавления встроенного подавления:[1]
if ( !pre ) {
trace("pre failed");
// cppcheck-suppress uninitvar
} else if ( !x ) {
trace("x failed");
} else {
trace("post failed");
}
и я также довел это до сведения разработчиков Cppcheck:
# 7663 (Ложно-положительный: неинициализированная переменная в недоступном коде)
[1] Я решил не инициализировать переменную. Это не из-за соображений производительности, но чтобы быть в курсе об ошибке, которая будет исправлена в следующем выпуске, когда Cppcheck скажет
Id: unmatchedSuppression
Summary: Unmatched suppression: uninitvar
Message: Unmatched suppression: uninitvar
Статический анализ, кажется, жалуется, потому что если pre
ложь, то x
никогда не устанавливается.
Ваш код структурирован так, что значение x
никогда не доступен, если pre
является false — я бы сказал, что в этом случае статический анализатор не дает полезного вывода.
Перечислим различные случаи, которые у нас есть (поэтому мы можем быть достаточно уверены, что это cppcheck, а не мы!):
Первое утверждение, в котором x
доступ находится в линии if ( !pre || !x || !post )
— из-за оценка короткого замыкания: if( A || B || C )
не оценивает B
или же C
если A
правда; следовательно, мы никогда не пытаемся читать неинициализированный x
(поскольку x
только неинициализирован, если pre
ложь, в этом случае мы перестали вычислять выражение!)
Второе использование в
if ( !pre ) {
trace("pre failed");
} else if ( !x ) { // <-- HERE Cppcheck complains
Опять же, мы можем попасть на оскорбительную линию, только если pre
было правдой (в этом случае x
правильно инициализирован).
Из этого можно сделать вывод, что либо:
Фактический код по ошибке пытается прочитать x
в каком-то состоянии даже есть pre
ложно, и вы упустили его при построении примера (иногда логический ход программы может быть немного тупым)
Статический анализатор ленив и замечает линию else if( !x )
и не может определить, достижима ли эта строка с неинициализированным значением.
Исходя из предоставленного вами кода, вы не должны беспокоиться: инструмент статического анализа технически правильно x
может быть неинициализирован, но в этих случаях он не используется (и, следовательно, вероятно, не должен вас предупреждать).
Я бы порекомендовал назначить x
значение по умолчанию, если вы не уверены, или если фактическая логика очень тупая.
Если твой pre
состояние false
чем х будет неинициализирован. На линии if ( !x )
CppCheck предупреждает об использовании неопределенного значения. Чтобы исправить это инициализировать x
переменная.