关于MISRA C 2012规则15.4 -“用于终止任何迭代语句的break或后藤语句不应超过一个。”-此示例正确吗?有人能用一些工具(MISRA检查器)来确认这一点吗?
do {
retval = do_smth();
if (retval != OK) {
break;
}
retval = do_smth2();
if (retval != OK) {
break;
}
retval = do_smth3();
} while (0u);
字符串
这只是一个概念,但我在这里尝试的是用break
的cascade替换goto
的cascade(不幸的是在这种情况下被禁止)。我的观点是do { } while(0u);
不是一个迭代语句。
你觉得呢?
7条答案
按热度按时间vecaoik11#
首先,您的代码确实没有遵循规则15.4,因为您在迭代语句中有3个
break
。但这只是一个建议,只要代码可读且易于理解,像您这样使用多个break并没有什么错。这些MISRA规则的主要理由是防止“复合语句意大利面条”,其中复杂的代码从多个嵌套的复合语句中分离出来。在盲目地遵循这些规则之前,理解其基本原理是很重要的。因此,在这种情况下,只需考虑保持代码不变-咨询规则不需要偏离。
否则,有几个选项,如下所示:
MISRA-C的一个问题是,它不允许从一个函数中多次返回,即使它使代码更具可读性。否则,最明显和最易读的解决方案将是使用函数:
字符串
我通常的解决方案是使MISRA-C永久偏离多重返回规则,并允许它在使代码更具可读性的情况下使用,就像在这种情况下一样。
否则,第二个最好的选择可能是旧的“on error后藤”-班宁
goto
的规则在MISRA-C:2012中被放宽,所以现在只是建议。型
如果以上两种形式都不合适,因为你对MISRA-C非常严格,那么第三种选择可能是这样的,我相信它100%符合MISRA-C:
型
我的观点是做{ } while(0 u);不是迭代语句。
C语言不同意你的观点。
1)C17:
6.8.5迭代语句
语法
while
(
* 表达式 *)
* 语句 *do
* 语句 *while
(
* 表达式 *) ;
oxiaedzo2#
我会把你的代码替换成这样:
字符串
顺便说一句:最后一次突破(
break; // <- 3rd
)无论如何都是无用的7hiiyaii3#
用于终止任何迭代语句的break或后藤语句不应超过一个。
你的例子在一个do-while(迭代语句)中有3个break,所以我认为它是不正确的。
break
是一个控制流/循环控制语句,仅在循环上下文中有效。我认为你的论点在这里站不住脚,尽管我明白你的意思。TL;DR:
do-while
仍然是一个迭代语句,尽管它只运行一次。字符串
ix0qys7i4#
我不知道这个代码是否足够好。不过,这很管用。
字符串
vjrehmav5#
我不是MISRA方面的Maven,所以这可能是因为其他原因而被禁止的,但在这种情况下,我可能会使用这样的东西:
字符串
无
goto
、无break
、无迭代、无重复测试。空语句看起来很奇怪,这是真的,尽管在实践中,经常会有一些错误日志代码放在那里。如果不喜欢裸分号,可以使用
{ }
或{ /* do nothing */ }
。条件语句中的赋值(如经典的
while((c = getchar()) != EOF)
循环)可能会让新手感到困惑(我怀疑MISRA可能或多或少地因为这个原因而禁止它们),但在许多情况下,如果你能容忍它们,它们真的可以帮助消除各种其他丑陋。0kjbasz66#
在过去的一个项目中,我引入了一个标准宏ER_CHK,在整个项目中使用
为清楚起见,将其简化为:
字符串
您可以按如下方式使用它:
型
这强制执行了一个单一的标准退出--使真实的的代码非常干净。
实际上,我定义了一个宏来包含发现故障的日志:例如,在
型
这在堆栈展开时提供日志“回溯”。
主要的一点是,这在整个项目中使用。它允许普通代码脱颖而出,并且有一种处理异常的标准方法,可以被视为一种习惯用法、模式或语言扩展。
它使正常(非异常)代码更具可读性,因为
有关更完整的描述,请参阅https://forum.misra.org.uk/archive/index.php?thread-368.html和C/C++ Users Journal上的完整文章“Exception Handling in Embedded C Programs”。
mpbci0fu7#
我的职位:
字符串
在(retval = KO)的情况下似乎更慢,但是……今天的编译器非常聪明。我很确定在真实的的编译中函数会立即返回。此外,在MISRA中,不要使用后藤,每个函数中只有一个return。