c++ - true - variable bool
La expresión ''i<0'' siempre es falsa (4)
Para el siguiente fragmento de código:
size_t i = 0;
std::wstring s;
s = (i < 0) ? L"ABC" : L"DEF";
s = (i != -1) ? L"ABC" : L"DEF";
El análisis de PVS-Studio registra una advertencia para la primera condición i < 0
, como se esperaba:
V547 Expression ''i < 0'' is always false. Unsigned type value is never < 0. test_cpp_vs2017.cpp 19
Expression ''i < 0'' is always false. Unsigned type value is never < 0. test_cpp_vs2017.cpp 19
¿Por qué PVS no emite ninguna advertencia sobre la segunda condición, también sospechosa, i != -1
informa que siempre es cierto, por ejemplo?
Cuando un valor se convierte en sin signo, si ese valor no es representable por el tipo sin signo, entonces el valor se convertirá en un valor (o más bien, el valor) que es representable, y es congruente con el valor original módulo el número de valores representables (que es el valor representable máximo + 1 == 2 n donde n es el número de bits).
Por lo tanto, no hay nada de qué advertir, porque hay un valor para el cual la condición puede ser falsa (siempre y cuando solo analicemos esa expresión de forma aislada. i
siempre es 0, entonces la condición siempre es verdadera, pero para poder demostrar que, debemos tener en cuenta toda la ejecución del programa).
-1 es congruente con m - 1 módulo m, por lo tanto, -1 siempre se convierte al valor máximo representable.
Esto se debe a las conversiones integrales implícitas en ambos casos. A size_t
debe ser un tipo sin signo de al menos 16 bits y, en su caso, tiene el tamaño suficiente. int
que si un argumento es size_t
y el otro un int
, el argumento int
se convierte en size_t
.
Al evaluar i < 0
, 0
se convierte en un tipo size_t
. Ambos operandos son size_t
por lo que la expresión siempre es false
.
Al evaluar i != -1
, el -1
se convierte en size_t
. Este valor será std::numeric_limits<size_t>::max()
.
Referencia: http://en.cppreference.com/w/cpp/language/implicit_conversion
Hubo respuestas significativas correctas, pero me gustaría hacer algunas aclaraciones. Desafortunadamente, un ejemplo de prueba se formó incorrectamente. Podemos escribir de esta manera:
void F1()
{
size_t i = 0;
std::wstring s;
s = (i < 0) ? L"ABC" : L"DEF";
s = (i != -1) ? L"ABC" : L"DEF";
}
En tal caso, el analizador emitirá dos advertencias V547 :
- V547 La expresión ''i <0'' siempre es falsa. El valor de tipo sin firmar nunca es <0. consoleapplication1.cpp 15
- V547 La expresión ''i! = - 1'' siempre es verdadera. consoleapplication1.cpp 16
( V519 también se llevará a cabo, pero no se relaciona con el problema).
Por lo tanto, la primera advertencia de V547 es imprimir porque la variable sin signo no puede ser menor que cero. Tampoco importa qué valor tenga la variable. Se emite la segunda advertencia porque el analizador reacciona cuando se asigna 0 a la variable i y esta variable no cambia en ninguna parte.
Ahora escribamos otro ejemplo de prueba para que el analizador no sepa nada sobre el valor 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";
}
Ahora solo habrá una advertencia V547:
- V547 La expresión ''i <0'' siempre es falsa. El valor de tipo sin firmar nunca es <0. consoleapplication1.cpp 22
El analizador no puede decir nada sobre la condición (i != -1)
. Es perfectamente normal y puede ser, por ejemplo, la comparación con npos
, como ya hemos notado.
Escribí esto en caso de que alguien decidiera probar un ejemplo de fuente utilizando PVS-Studio, eliminándolo de la pregunta. Esta persona se sorprenderá cuando vea dos advertencias, aunque se discute que solo habrá una.
Porque eso sería una advertencia inútil, inválida. size_t
es un tipo sin signo, y debido a la forma en que funcionan las conversiones de enteros (ver [conv.integral] / 2), -1
convertido (implícitamente aquí) a size_t
es igual a SIZE_MAX
.
Considere el hecho de que esta es la definición real de std::string::npos
en libstdc ++:
static const size_type npos = static_cast<size_type>(-1);
Si PVS-Studio advirtió sobre i != -1
, ¿también debería advertir sobre i != std::string::npos
?
Por otro lado, un valor sin signo nunca puede ser menor que 0, debido a que no está firmado, por lo que es probable que i < 0
no sea lo que quería el programador y, por lo tanto, la advertencia está justificada.