Учитывая переменные a
, b
и c
:
uint32_t a;
uint16_t b, c;
Согласно стандарту MISRA-C 2012, выражение a+b+c
соответствует, тогда как b+c+a
не соответствует.
Почему?
Учитывая переменные a
, b
и c
:
uint32_t a;
uint16_t b, c;
Согласно стандарту MISRA-C 2012, выражение a+b+c
соответствует, тогда как b+c+a
не соответствует.
Почему?
С u16a+u16b+u32c
u16a+u16b
представляет собой unsigned
(думаю, 16-битное) сложение с потенциальным переполнением, которое теряется до последующего добавления к u32c
.
u32a+u16b+u16c
добавляет u32a+u16b
, а затем использует этот 32-битный результат при добавлении 16c
, предотвращая эту потерю.
Пример
0x8000 + 0x8000 + 0x10000
(0x8000 + 0x8000) + 0x10000
0 + 0x10000
0x10000
vs.
0x10000 + 0x8000 + 0x8000
(0x10000 + 0x8000) + 0x8000
0x18000 + 0x8000
0x20000
Поскольку C позволяет автоматически выполнять присваивания между различными арифметическими типами, использование этих неявных преобразований может привести к непреднамеренным результатам с потенциальной потерей значения, знака или точности. MISRA_C:2012 применяет строгую типизацию с помощью своей модели «основного типа», чтобы предупреждать, когда это может произойти, — известные как правила 10.x.
В этом случае существует вероятность потери переполнения с u16a+u16b+u32c
В частности, это нарушение MISRA C:2012 Rule-10.7: «Если составное выражение используется как один операнд оператора, в котором выполняются обычные арифметические преобразования, то другой операнд не должен иметь более широкий существенный тип».
Распространенной ошибкой является предположение, что на оценку влияет более широкий тип. Тип выражения фактически определяется типом его операндов после любого целочисленного расширения. Вы можете исправить это, приведя к более широкому типу или переставив операнды в начале выражения, как показано в первом примере: u32a+u16b+u16c
Примечание: это не означает, что все операнды в выражении относятся к одному и тому же существенному типу. Выражение u32a + u16b + u16c соответствует требованиям, так как оба сложения теоретически будут выполняться в типе uint32_t.