web-dev-qa-db-fra.com

L'expression «i <0» est toujours fausse

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?

25
mloskot

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é.

36
Fanael

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

22
Bathsheba

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.

7
eerorika

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:

  • V547 L'expression 'i <0' est toujours fausse. La valeur du type non signé n'est jamais <0. consoleapplication1.cpp 15
  • V547 L'expression 'i! = - 1' est toujours vraie. consoleapplication1.cpp 16

( 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:

  • V547 L'expression 'i <0' est toujours fausse. La valeur du type non signé n'est jamais <0. consoleapplication1.cpp 22

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.

1
AndreyKarpov