为什么MISRA-C:2004会在这里引发错误?

时间:2015-01-05 11:53:00

标签: c misra

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

#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));
    //...
}

1 个答案:

答案 0 :(得分:1)

这条线是一个难以理解的混乱。考虑将其拆分以提高可读性。 根据系统中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涉及隐式整数类型促销。如果你像上面那样拆分代码,那么你就不会对每个子表达式的“底层类型”感到困惑。你做错了是在操作之前向底层类型添加一个强制转换,这没什么用。 每次操作后都需要

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

解释上面的代码:

第一行显式转换为uint32_t,以确保intNumber1U的类型相同。这样,子表达式intNumber + 1U没有隐式转换,这是与底层类型uint8_t相同的更广泛类型的签名(意味着它是安全的)。添加的结果是unsigned int类型。同样,unsigned int & unsigned int不会产生隐式转换。最后,结果转换为uint8_t以满足许多MISRA规则。其余代码以相同的方式继续。

我总是尝试在操作之前对一个大整数类型进行扩展转换,以简化所有操作,避免隐式促销并避免相互之后的多次转换。

请注意,规则10.1的真正目的实际上是强迫您自己教育C中的隐式类型促销。这是一个相当复杂的主题,但是令人恐惧的C程序员无法输入促销和所有危险和他们造成的错误。 More info about the type promotion rules here