Диагностическое правило основано на руководстве MISRA (Motor Industry Software Reliability Association) по разработке программного обеспечения.
Диагностическое правило актуально только для C.
Язык C предоставляет свободу при проведении присваиваний между объектами различных арифметических типов. Однако неявные преобразования при подобных присваиваниях могут приводить к неочевидным проблемам, таким как потеря знака, точности или значимости.
Рассмотрим следующий фрагмент кода:
void foo()
{
....
uint16_t var_a = 30000;
uint16_t var_b = 40000;
uint32_t var_sum;
var_sum = var_a + var_b; /* var_sum = 70000 or 4464? */
....
}
При вычислении значения, которое будет присвоено переменной var_sum, происходит неявное преобразование из типа uint16_t к int. Как следствие, результат присваивания зависит от размера типа int:
int имеет 32-битный размер, то вычисления будут выполнены по модулю 2^32, и в переменную var_sum будет записано ожидаемое значение 70000;int имеет 16-битный размер, то вычисления будут выполнены по модулю 2^16, и в переменную var_sum будет записано значение 70000 % 65536 == 4464.Стандарт MISRA C определяет собственную модель типов — Essential type model.
Используя модель сущностных типов, можно уменьшить количество подобных неочевидных проблем. Для этого следует избегать присвоения составных выражений, имеющих меньший сущностный тип, в переменные и аргументы функций, имеющие более широкий сущностный тип.
Код выше можно исправить, используя явное преобразование к uint32_t:
void foo()
{
....
uint16_t var_a = 30 000;
uint16_t var_b = 40 000;
uint32_t var_sum;
var_sum = (uint32_t)var_a + var_b; /* var_sum = 70 000 */
....
};
Теперь вычисления происходят по модулю 2^32 независимо от того, какой размер имеет int, и ошибка не возникает, даже если int имеет 16-битный размер.
Данная диагностика классифицируется как:
|