Проблема в том, что целочисленные продвижения молча переводят как процент, так и процент в тип "int".Следовательно, умножение выполняется для типа со знаком.
Код, совместимый с MISRA, должен либо переписать код как
uint16_t basic_units = (uint16_t)rate * (uint16_t)percentage;
, либо сделать так, как предлагает MISRA, немедленно типизировать результат выражения в его«базовый тип»:
uint16_t basic_units = (uint8_t)(rate * percentage);
РЕДАКТИРОВАТЬ: разъяснение следует.
ISO 9899: 1999 6.3.1.1 2
Еслиint может представлять все значения исходного типа, значение преобразуется в int;в противном случае он конвертируется в беззнаковое целое.Они называются целочисленными повышениями .
Информационный текст от MISRA-C:
MISRA-C: 2004 6.10.3 Преобразования опасных типов:
/ - /
- Изменение подписи в арифметических операциях: Интегральное продвижение часто приводит к двум беззнаковым операндам, приводящим к результату типа (подпись)INT .Например, добавление двух 16-разрядных операндов без знака даст 32-разрядный результат со знаком, если int составляет 32 бита, но 16-разрядный результат без знака, если int - 16 бит.
На самом деле я не уверен, удовлетворяет ли MISRA 2-я строка выше, если подумать, возможно, я перепутал MISRA 10.1 с 10.5, где последний обеспечивает немедленное приведение к базовому типу., но только в случае некоторых побитовых операторов.
Я протестировал обе строки с помощью статического анализа кода LDRA, и он не жаловался (но выдает несколько неправильных, не связанных предупреждений), но затем LDRA также работает очень плохов MISRA-C.
В любом случае, проблема в исходном вопросе заключается в том, что процент и процент неявно преобразуются целочисленными повышениями в тип int , который подписан, поскольку int может представлять все значения uint8_t.Таким образом, это становится
uint16_t basic units = (int)rate * (int)percentage.
Чтобы предотвратить это, вы должны явно указать тип.Подумав об этом больше, я пойду с 1-й строкой из моих двух выше.