Pour l'extrait de code suivant:
size_t i = 0;
std::wstring s;
s = (i < 0) ? L"ABC" : L"DEF";
s = (i != -1) ? L"ABC" : L"DEF";
L'analyse PVS-Studio enregistre un avertissement pour la première condition i < 0
, comme prévu:
V547Expression 'i < 0' is always false. Unsigned type value is never < 0. test_cpp_vs2017.cpp 19
Pourquoi PVS n'émet aucun avertissement concernant la seconde condition, également suspecte i != -1
le signalant comme toujours vrai, par exemple?
Parce que ce serait un avertissement inutile et invalide. size_t
est un type non signé, et en raison du fonctionnement des conversions d'entiers (voir [conv.integral]/2), -1
converti (implicitement ici) en size_t
est égal à SIZE_MAX
.
Considérez qu'il s'agit de la définition réelle de std::string::npos
dans libstdc ++:
static const size_type npos = static_cast<size_type>(-1);
Si PVS-Studio met en garde contre i != -1
, faudrait-il également avertir i != std::string::npos
?
D'un autre côté, une valeur non signée ne peut jamais être inférieure à 0, car elle n'est pas signée, donc i < 0
n'est probablement pas ce que le programmeur voulait, et donc l'avertissement est justifié.
Cela est dû à conversions intégrales implicites dans les deux cas. Un size_t
doit être un type non signé d'au moins 16 bits et dans votre cas, il est de taille suffisante cf. int
que si un argument est size_t
et l'autre un int
, alors l'argument int
est converti en size_t
.
Lors de l'évaluation de i < 0
, 0
Est converti en un type size_t
. Les deux opérandes sont size_t
Donc l'expression est toujours false
.
Lors de l'évaluation de i != -1
, Le -1
Est également converti en size_t
. Cette valeur sera std::numeric_limits<size_t>::max()
.
Référence: http://en.cppreference.com/w/cpp/language/implicit_conversion
Lorsqu'une valeur est convertie en non signé, si cette valeur n'est pas représentable par le type non signé, alors la valeur sera convertie en une valeur (ou plutôt, la valeur) qui est = représentable, et est congru à la valeur d'origine modulo le nombre de valeurs représentables (qui est la valeur maximale représentable + 1 == 2n où n est le nombre de bits).
Par conséquent, il n'y a rien à avertir, car il existe une valeur pour laquelle la condition peut être fausse (tant que nous analysons uniquement cette expression de manière isolée. i
est toujours 0, donc la condition est toujours vraie, mais pour pouvoir le prouver, il faut prendre en compte l'intégralité de l'exécution du programme).
-1 est congru avec m - 1 modulo m, donc -1 est toujours converti en la valeur représentable maximale.
Il y avait de bonnes réponses significatives, mais je voudrais apporter quelques clarifications. Malheureusement, un exemple de test a été mal formé. Nous pouvons écrire de cette façon:
void F1()
{
size_t i = 0;
std::wstring s;
s = (i < 0) ? L"ABC" : L"DEF";
s = (i != -1) ? L"ABC" : L"DEF";
}
Dans ce cas, l'analyseur émettra deux V547 avertissements:
( V519 aura également lieu, mais cela ne concerne pas le problème.)
Ainsi, le premier avertissement V547 est imprimé car la variable non signée ne peut pas être inférieure à zéro. Peu importe également la valeur de la variable. Le deuxième avertissement est émis parce que l'analyseur réagit que 0 est affecté à la variable i et que cette variable ne change nulle part.
Écrivons maintenant un autre exemple de test pour que l'analyseur ne sache rien de la valeur de la variable i
:
void F2(size_t i)
{
std::wstring s;
s = (i < 0) ? L"ABC" : L"DEF";
s = (i != -1) ? L"ABC" : L"DEF";
}
Maintenant, il n'y aura qu'un seul avertissement V547:
L'analyseur ne peut rien dire sur le (i != -1)
condition. C'est parfaitement normal et cela peut être, par exemple, la comparaison avec npos
, comme nous l'avons déjà remarqué.
J'ai écrit cela au cas où quelqu'un décide de tester un exemple de source à l'aide de PVS-Studio, le rendant hors de question. Cette personne sera surprise quand elle verra deux avertissements, bien qu'il soit discuté qu'il n'y en aura qu'un.