В выражении присутствует операция умножения или деления целочисленных типов данных. Полученное значение неявно преобразуется к типу с плавающей точкой. Обнаружив такую ситуацию, анализатор предупреждает о наличии потенциальной ошибки, которая может привести к переполнению или к вычислению неточного результата.
Рассмотрим возможные ошибки на примерах.
Ситуация первая. Переполнение.
int LX = 1000;
int LY = 1000;
int LZ = 1000;
int Density = 10;
double Mass = LX * LY * LZ * Density;
Мы хотим вычислить массу объекта, зная его плотность и размеры. Мы знаем, что результирующее значение может быть большим. Поэтому, переменная 'Mass' имеет тип 'double'. Однако этот код не учитывает, что перемножаются переменные типа 'int'. В результате, в правой части выражения произойдет целочисленное переполнение и результат будет некорректен.
Исправить ситуацию можно двумя способами. Можно изменить типы переменных:
double LX = 1000.0;
double LY = 1000.0;
double LZ = 1000.0;
double Density = 10.0;
double Mass = LX * LY * LZ * Density;
Другой способ - это использовать явное приведение типов:
int LX = 1000;
int LY = 1000;
int LZ = 1000;
int Density = 10;
double Mass = (double)(LX) * LY * LZ * Density;
Достаточно привести к типу 'double' только первую переменную. Поскольку операция умножения относится к лево-ассоциативным операторам, то вычисление будет происходить следующим образом: (((double)(LX) * LY) * LZ) * Density. В результате каждый из операндов перед умножением будет преобразовываться к типу 'double' и мы получим корректный результат.
P.S. Напомним, что вот так, делать неправильно: Mass = (double)(ConstMass) + LX * LY * LZ * Density. Выражение справа от оператора '=' будет иметь тип 'double'. Но перемножаться будут по-прежнему переменные типа 'int'.
Ситуация вторая. Потеря точности.
int totalTime = 1700;
int operationNum = 900;
double averageTime = totalTime / operationNum;
Программист может ожидать, что переменная 'averageTime' будет иметь значение '1.888(8)', однако при выполнении программы будет получен результат равный '1.0'. Это происходит потому, что операция деления выполняется с целочисленными типами и только затем приводится к типу с плавающей точкой.
Как и в предыдущем случае, ошибку можно исправить 2 способами.
Первый способ - изменить типы переменных:
double totalTime = 1700;
double operationNum = 900;
double averageTime = totalTime / operationNum;
Второй способ - использовать явное приведение типов.
int totalTime = 1700;
int operationNum = 900;
double averageTime = (double)(totalTime) / operationNum;
Примечание
Естественно, в некоторых случаях нужно произвести именно целочисленное деление. В таких случаях, чтобы скрыть ложное предупреждение, можно использовать комментарий вида:
//-V636
См. также: Документация. Подавление ложных предупреждений.
Данная диагностика классифицируется как:
|
Взгляните на примеры ошибок, обнаруженных с помощью диагностики V636. |