Данное диагностическое правило основано на руководстве 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 определена модель сущностных типов (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-битный размер.
Данная диагностика классифицируется как:
|