为什么 MISRA-C:2004 在这里抛出错误



我似乎不断收到以下代码片段中 lShift 分配的 MISRA-C:2004 规则 10.1 和 10.3 错误,并且无法真正看到还可以做些什么来满足要求......为什么我仍然收到错误?

#define ADC_INTSELxNy_LOG2_NUMBITS_PER_REG 3U
#define ADC_INTSELxNy_NUMBITS_PER_REG 8U
void foo (const bar_e intNumber) {
    uint_least8_t lShift = (uint_least8_t)(ADC_INTSELxNy_NUMBITS_PER_REG - (((((uint_least8_t)intNumber) + 1U) & 0x1U) << ADC_INTSELxNy_LOG2_NUMBITS_PER_REG));
    //...
}

那一行是一团乱麻。考虑将其拆分以提高可读性。根据系统上 int 的宽度,代码看起来会有所不同。下面的代码假定为 32 位整数。

uint8_t        bit      = (uint8_t)( ((uint32_t)intNumber + 1U) & 0x1U );
uint32_t       lShift32 = ((uint32_t)bit << ADC_INTSELxNy_LOG2_NUMBITS_PER_REG);
uint_least8_t  lShift8  = (uint_least8_t)((uint32_t)ADC_INTSELxNy_NUMBITS_PER_REG - lShift);

现在,至于出现错误的原因,规则 10.1 和 10.3 与隐式整数类型升级有关。如果你像我上面所做的那样拆分代码,你就不会那么困惑每个子表达式的"底层类型"是什么。您做错了在操作之前将强制转换添加到基础类型,这没有什么好处。您需要在每次操作执行此操作。

+ 操作

需要在 + 操作之后显式强制转换为基础类型,与 & 操作和移位操作相同。仅仅将所有内容强制转换为最后的基础类型是不够的,您必须单独考虑每个子表达式。

为了解释我上面的代码:

第一行具有要uint32_t的显式强制转换,以确保intNumber1U的类型相同。这样,子表达式intNumber + 1U就不会隐式转换,这是一种更广泛的类型,与基础类型uint8_t具有相同的符号(意味着它是安全的)。添加的结果是无符号 int 类型。同样,unsigned int & unsigned int不会产生隐式转换。最后,结果被投射到uint8_t以满足许多MISRA规则。代码的其余部分以相同的方式进行。

我总是尝试在操作之前将转换扩大到大整数类型,以简化所有内容,避免隐式提升并避免彼此之后的大量转换。

请注意,规则 10.1 的真正目的是迫使您了解 C 语言中的隐式类型提升。这是一个相当复杂的话题,但是数量惊人的C程序员忘记了类型推广以及由此引起的所有危险和错误。有关类型升级规则的详细信息,请参阅此处。

最新更新