C 中的 MISRA 递增

MISRA incrementation in C

在调试一些嵌入式代码时,我遇到了这样的事情:

buffPtr = &a[5];
buffEndPtr = &a[10];

while (buffPtr != buffEndPtr) 
{ 
    *buffPtr = 0xFF; 
    buffPtr  = &buffPtr[1];         /*  MISRA improvement for: buffPtr++ */ 
}

为什么这个构造是对 (*buffPtr)++ 的改进?

有一条 MISRA 规则规定唯一允许的指针数学是索引操作。

您显示的模式是执行不力的解决方法。它是 ugly/weird/uncommon 并且可能是基于对该规则的目的的误解。它也可能违反了另一条规则。

编写此代码的更好方法是:

for(i=5; i < 10; i++)
{
    a[i] = 0xff;
}

2015 年 5 月 20 日更新 - 因为这是公认的答案,这里是实际违反的规则,由 embedded.kyle 提供:

MISRA-C:2004, Rule 17.4 (Required) or MISRA-C:2012, Rule 18.4 (Required) Array indexing shall be the only allowed form of pointer arithmetic.

(*buffPtr)++违反的规则是:

MISRA-C:2004, Rule 17.4 (Required) or MISRA-C:2012, Rule 18.4 (Required)

Array indexing shall be the only allowed form of pointer arithmetic.

这条规则背后的原因:

Array indexing using the array subscript syntax, ptr[expr], is the preferred form of pointer arithmetic because it is often clearer and hence less error prone than pointer manipulation. Any explicitly calculated pointer value has the potential to access unintended or invalid memory addresses. Such behavior is also possible with array indexing, but the subscript syntax may ease the task of manual review.

Pointer arithmetic in C can be confusing to the novice The expression ptr+1 may be mistakenly interpreted as the addition of 1 to the address held in ptr. In fact the new memory address depends on the size in bytes of the pointer's target. This misunderstanding can lead to unexpected behaviour if sizeof is applied incorrectly.

MISRA 的许多规则具有相似的原理。基本上他们的思维过程是,如果您尽可能简单和明确地编写代码,代码将更具可读性和可维护性,因此会导致代码本质上更安全。更安全的代码是 MISRA 标准背后的目的。

正如 Brian 所指出的,有一些方法可以编写符合 MISRA 标准但仍然违反规则背后意图的代码。在我看来,Brian 的 for 循环示例将是最常见且最容易理解的结构。

在 MISRA-C:2004 规则 17.4 中,有一条禁止所有形式的指针运算的咨询规则。意图是好的,该规则的目的是试图禁止具有潜在危险的代码,例如:

stuff* p; 
p = p + 5; // 5 stuff, not 5 bytes, bug or intentional?

和难以阅读的代码,例如

*(p + 5) = something;  // harder to read but equivalent to p[5]

通常,目的是建议在遍历指向的数据时使用整数迭代器而不是指针算法。

但是,该规则还禁止了各种可能不危险的基本指针操作,例如 ptr++。一般来说,规则太严格了。

在 MISRA-C:2012 中,此规则 (18.4) 放宽为仅禁止 + - += -= 运算符。


在您的案例中,buffPtr = &buffPtr[1]; 是一种试图规避规则 17.4 的错误尝试,因为该规则没有多大意义。相反,程序员决定混淆他们的程序,使其可读性降低,因此安全性降低。

处理此问题的正确方法是使用 ++ 运算符并忽略规则 17.4。这是一个建议规则,所以不需要做任何偏差(除非本地 MISRA-C 实施出于某种原因另有说明)。如果您确实需要偏离,您可以简单地说该规则对 ++ 运算符没有任何意义,然后参考 MISRA-C:2012 18.4.

(当然,将整个循环重写为另一个答案中的for循环是最好的解决方案)

不使用常识进行编程总是非常危险的,就像盲目遵循 MISRA 而不理解规则背后的合理理由一样,或者在这种情况下缺乏这样的理由。