C中的MISRA增量

时间:2015-05-14 14:02:02

标签: c pointers embedded misra

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

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

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

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

3 个答案:

答案 0 :(得分:12)

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

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

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

 if(cartime<=first){
            second=first;
        secode=firstcode;
        first=cartime;
        firstcode=carcode;
    }

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

  

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

答案 1 :(得分:10)

(*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循环示例将是最常见且易于理解的构造。

答案 2 :(得分:5)

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