MISRA C 2012 规则 15.4 并用 break 替换 goto
MISRA C 2012 Rule 15.4 and replacing goto's with break's
关于 MISRA C 2012 规则 15.4 -“用于终止任何迭代语句的 break 或 goto 语句不应超过一个。” - 这个例子正确吗?谁能用某种工具(MISRA 检查器)确认这一点?
do {
retval = do_smth();
if (retval != OK) {
break;
}
retval = do_smth2();
if (retval != OK) {
break;
}
retval = do_smth3();
} while (0u);
这只是一个概念,但我在这里尝试的是用 break
的级联替换 goto
的级联(不幸的是在这种情况下被禁止)。我的观点是 do { } while(0u);
不是迭代语句。
你怎么看?
There should be no more than one break or goto statement used to terminate any iteration statement.
您的示例在一个 do-while(迭代语句)中有 3 个中断,所以我认为这是不正确的。 break
是 control-flow/loop-control 语句,仅在循环上下文中有效。我不认为你的论点在这里有效,虽然我明白你要去哪里。
TL;DR: do-while
仍然是一个迭代语句,即使它只运行一次。
do {
retval = do_smth();
if (retval != OK) {
break; // <- 1st
}
retval = do_smth2();
if (retval != OK) {
break; // <- 2nd
}
retval = do_smth3();
if (retval != OK) {
break; // <- 3rd
}
} while (0u);
我会用这个替换你的代码:
retval = do_smth();
if (retval == OK) {
retval = do_smth2();
}
if (retval == OK) {
retval = do_smth3();
}
- 没有假的而
- 没有伪装成 break 的 goto
- 因此连一个都没有 goto/break
- 因此不再有 MISRA 问题
- 奖励:行数比原始代码少一半
顺便说一句:最后一次休息(break; // <- 3rd
)反正没用
首先,您的代码确实不遵循规则 15.4,因为您在迭代语句中有 3 break
1)。但这只是一个建议,只要代码可读且易于遵循,像您一样使用多个中断没有错。
这些 MISRA 规则的主要原理是防止复杂代码从多个嵌套复合语句中分离出来的“复合语句面条”。在盲目遵循这些规则之前了解其基本原理很重要。因此,在这种情况下,只需考虑保留代码原样 - 建议规则不需要任何偏差。
否则,有如下几个选项:
MISRA-C 的一个问题是它不允许来自一个函数的多个 return,即使它使代码更具可读性。否则,最明显和最易读的解决方案是使用函数:
type do_stuff (void);
{
type retval;
retval = do_smth();
if (retval != OK) { return retval; }
retval = do_smth2();
if (retval != OK) { return retval; }
retval = do_smth3();
return retval;
}
我通常的解决方案是使 MISRA-C 永久偏离多重 return 规则,并在它使代码 more 可读的情况下允许它,比如在这种情况下是这样。
否则,第二个最佳选择可能是旧的“错误转到”- 禁止 goto
的规则在 MISRA-C:2012 中放宽了,所以现在只是建议。
retval = do_smth();
if (retval != OK) { goto error; }
retval = do_smth2();
if (retval != OK) { goto error; }
retval = do_smth3();
if (retval != OK) { goto error; }
goto everything_ok;
error:
/* error handling */
everything_ok:
如果因为您对 MISRA-C 非常严格,所以以上两种形式都不行,那么第三个选项可能是这样的,我认为它是 100% MISRA-C 兼容的:
typedef type do_stuff_t (void);
do_stuff_t* const do_stuff[N] = { do_smth, do_smth2, do_smth3 };
type retval = OK;
for(uint32_t i=0u; (i<N) && (retval==OK); i++)
{
retval = do_stuff[i]();
}
My point is that do { } while(0u); is not an iteration statement.
C语言不同意你的看法
1) 来自 C17:
6.8.5 Iteration statements
Syntax
iteration-statement:
while
(
expression )
statement
do
statement while
(
expression ) ;
我不是 MISRA 方面的专家,所以这可能出于其他原因被禁止,但在这种情况下我可能会想使用这样的东西:
if((retval = do_smth()) != OK)
;
else if((retval = do_smth2()) != OK)
;
else if((retval = do_smth3()) != OK)
;
无goto
,无break
,无迭代,无重复测试。
空语句看起来很奇怪,这是真的,虽然在实践中,经常会有一些错误记录代码放在那里。如果裸分号不符合您的口味,您可以使用 { }
或 { /* do nothing */ }
.
条件语句中的赋值(如经典的 while((c = getchar()) != EOF)
循环)可能会让新手感到困惑(我怀疑 MISRA 可能或多或少出于这个原因禁止它们),但在很多情况下,如果你可以容忍它们,它们真的可以帮助消除其他各种丑陋。
我不知道这段代码是否足够好。虽然它有效。
switch(0) {
default:
retval = do_smth();
if (retval != OK) {
break;
}
retval = do_smth2();
if (retval != OK) {
break;
}
retval = do_smth3();
break;
}
关于 MISRA C 2012 规则 15.4 -“用于终止任何迭代语句的 break 或 goto 语句不应超过一个。” - 这个例子正确吗?谁能用某种工具(MISRA 检查器)确认这一点?
do {
retval = do_smth();
if (retval != OK) {
break;
}
retval = do_smth2();
if (retval != OK) {
break;
}
retval = do_smth3();
} while (0u);
这只是一个概念,但我在这里尝试的是用 break
的级联替换 goto
的级联(不幸的是在这种情况下被禁止)。我的观点是 do { } while(0u);
不是迭代语句。
你怎么看?
There should be no more than one break or goto statement used to terminate any iteration statement.
您的示例在一个 do-while(迭代语句)中有 3 个中断,所以我认为这是不正确的。 break
是 control-flow/loop-control 语句,仅在循环上下文中有效。我不认为你的论点在这里有效,虽然我明白你要去哪里。
TL;DR: do-while
仍然是一个迭代语句,即使它只运行一次。
do {
retval = do_smth();
if (retval != OK) {
break; // <- 1st
}
retval = do_smth2();
if (retval != OK) {
break; // <- 2nd
}
retval = do_smth3();
if (retval != OK) {
break; // <- 3rd
}
} while (0u);
我会用这个替换你的代码:
retval = do_smth();
if (retval == OK) {
retval = do_smth2();
}
if (retval == OK) {
retval = do_smth3();
}
- 没有假的而
- 没有伪装成 break 的 goto
- 因此连一个都没有 goto/break
- 因此不再有 MISRA 问题
- 奖励:行数比原始代码少一半
顺便说一句:最后一次休息(break; // <- 3rd
)反正没用
首先,您的代码确实不遵循规则 15.4,因为您在迭代语句中有 3 break
1)。但这只是一个建议,只要代码可读且易于遵循,像您一样使用多个中断没有错。
这些 MISRA 规则的主要原理是防止复杂代码从多个嵌套复合语句中分离出来的“复合语句面条”。在盲目遵循这些规则之前了解其基本原理很重要。因此,在这种情况下,只需考虑保留代码原样 - 建议规则不需要任何偏差。
否则,有如下几个选项:
MISRA-C 的一个问题是它不允许来自一个函数的多个 return,即使它使代码更具可读性。否则,最明显和最易读的解决方案是使用函数:
type do_stuff (void);
{
type retval;
retval = do_smth();
if (retval != OK) { return retval; }
retval = do_smth2();
if (retval != OK) { return retval; }
retval = do_smth3();
return retval;
}
我通常的解决方案是使 MISRA-C 永久偏离多重 return 规则,并在它使代码 more 可读的情况下允许它,比如在这种情况下是这样。
否则,第二个最佳选择可能是旧的“错误转到”- 禁止 goto
的规则在 MISRA-C:2012 中放宽了,所以现在只是建议。
retval = do_smth();
if (retval != OK) { goto error; }
retval = do_smth2();
if (retval != OK) { goto error; }
retval = do_smth3();
if (retval != OK) { goto error; }
goto everything_ok;
error:
/* error handling */
everything_ok:
如果因为您对 MISRA-C 非常严格,所以以上两种形式都不行,那么第三个选项可能是这样的,我认为它是 100% MISRA-C 兼容的:
typedef type do_stuff_t (void);
do_stuff_t* const do_stuff[N] = { do_smth, do_smth2, do_smth3 };
type retval = OK;
for(uint32_t i=0u; (i<N) && (retval==OK); i++)
{
retval = do_stuff[i]();
}
My point is that do { } while(0u); is not an iteration statement.
C语言不同意你的看法
1) 来自 C17:
6.8.5 Iteration statements
Syntax
iteration-statement:
while
(
expression)
statement
do
statementwhile
(
expression) ;
我不是 MISRA 方面的专家,所以这可能出于其他原因被禁止,但在这种情况下我可能会想使用这样的东西:
if((retval = do_smth()) != OK)
;
else if((retval = do_smth2()) != OK)
;
else if((retval = do_smth3()) != OK)
;
无goto
,无break
,无迭代,无重复测试。
空语句看起来很奇怪,这是真的,虽然在实践中,经常会有一些错误记录代码放在那里。如果裸分号不符合您的口味,您可以使用 { }
或 { /* do nothing */ }
.
条件语句中的赋值(如经典的 while((c = getchar()) != EOF)
循环)可能会让新手感到困惑(我怀疑 MISRA 可能或多或少出于这个原因禁止它们),但在很多情况下,如果你可以容忍它们,它们真的可以帮助消除其他各种丑陋。
我不知道这段代码是否足够好。虽然它有效。
switch(0) {
default:
retval = do_smth();
if (retval != OK) {
break;
}
retval = do_smth2();
if (retval != OK) {
break;
}
retval = do_smth3();
break;
}