C中的MISRA增量

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C中的MISRA增量相关的知识,希望对你有一定的参考价值。

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

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

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

为什么这个结构会改进(* buffPtr)++?

答案

有一个MISRA规则,规定允许的唯一指针是索引操作。

您展示的模式是执行不良的解决方案。这是丑陋/怪异/不常见,可能是基于对该规则的目的的误解。它也可能违反另一条规则。

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

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

更新2015-05-20 - 由于这是接受的答案,这里违反了实际规则,由embedded.kyle提供:

MISRA-C:2004,规则17.4(必需)或MISRA-C:2012,规则18.4(必需)数组索引应是唯一允许的指针算术形式。

另一答案

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

MISRA-C:2004,规则17.4(必填)或MISRA-C:2012,规则18.4(必填)

数组索引应该是唯一允许的指针算术形式。

他们在这条规则背后的推理:

使用数组下标语法ptr[expr]进行数组索引是指针运算的首选形式,因为它通常比指针操作更清晰,因此更不容易出错。任何显式计算的指针值都有可能访问非预期或无效的内存地址。使用数组索引也可以实现这种行为,但下标语法可以简化手动审查的任务。

C中的指针算法可能会让新手感到困惑。表达式ptr+1可能被错误地解释为1添加到ptr中的地址。实际上,新的内存地址取决于指针目标的字节大小。如果错误地应用sizeof,这种误解可能会导致意外行为。

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而不理解规则背后的合理原理,或者在这种情况下缺乏这样的规则。

以上是关于C中的MISRA增量的主要内容,如果未能解决你的问题,请参考以下文章

C 语言编码规范(MISRA-C-:2004)

C 语言编码规范(MISRA-C-:2004)

MISRA C 2012 - 规则 21.1 - 以下划线开头的宏

是否合法写入并集中的字节数组并从int读取以在MISRA C中转换值?

MISRA C ++(规则18-4-1)和动态内存分配 - 是否允许使用std :: string?

MISRA C:2012 8 Rules 8.1 A Standard C environment