米斯拉在C
在调试一些嵌入式代码时,我遇到了如下情况:米斯拉在C,c,pointers,embedded,misra,C,Pointers,Embedded,Misra,在调试一些嵌入式代码时,我遇到了如下情况: buffPtr = &a[5]; buffEndPtr = &a[10]; while (buffPtr != buffEndPtr) { *buffPtr = 0xFF; buffPtr = &buffPtr[1]; /* MISRA improvement for: buffPtr++ */ } 为什么这个构造比(*buffPtr)+?有一个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;
}
(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标准背后的目的
正如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而不理解规则背后的合理原理,或者在这种情况下不理解规则背后的合理原理。因为
(*bufftr)+
是错误的。你的意思是*bufftr++=0xFF代码>?@mch我想这是问题正文中的一个输入错误。查看代码中的注释。原始代码肯定是规则的“变通”,而不是因为它们而“改进”。for循环是正确的模式。是的,仔细想想,我猜memset
本身甚至不符合MISRA。因此,即使在可行的情况下,根据MISRA,这也不是正确的方法。更正:MISRA-C:2012允许+,但不允许+。它与MISRA-C:2004中引用的规则不同,也更为宽松。我认为该规则的意图是要求所有指针对象标识分配的开始,这是其他语言(如标准Pascal)的语义限制。具有这种语义限制的C方言无法完成C中可以完成的所有工作,但这种方言的实现可以以“全功能”C中无法实现的方式支持数组边界检查。在某些需要故障安全的系统中,编译器支持的数组边界检查可能会有所帮助。