我正在尝试摆脱代码中的多个break和goto语句。 正如规则所示,我们不应在任何迭代语句中使用多个break或goto语句
示例代码:
for(int32_t i = 0; i < 10; i++) {
if (i == number1) {
return_val = 2*number1 + number2;
break;
}
number1 += (5 * number2 + 2*number3);
if (i == number2) {
return_val = number1 + (3 * number3);
break;
}
number1 += 2 * number3;
if (i == number3) {
return_val = number1 + (2 * number2);
}
}
我尝试过使用嵌套 if 语句,但这不是终止循环的解决方案。
并且如果存在 goto 语句,而不是中断,那么可以解决这个问题。
带有 goto 的示例代码:
for(int32_t i = 0; i < 10; i++) {
if (i == number1) {
return_val = 2*number1 + number2;
goto LABE1;
}
number1 += (5 * number2 + 2*number3);
if (i == number2) {
return_val = number1 + (3 * number3);
goto LABE2;
}
number1 += 2 * number3;
if (i == number3) {
return_val = number1 + (2 * number2);
}
}
最佳答案
我认为 15.4 和 15.5 是两个极具争议的 MISRA 建议。请记住,它们不是必需的,而是建议性的,然后您可以将它们分类(如果您的组织批准)为“已取消”( tnx Andrew )。在我看来,遵循这些规则将使您的代码更加冗长、难以阅读,并且更容易出错。
正如我所说,这只是我的意见,让我们尝试一步一步的方法。我没有使用正确的名称,但您必须从您的域中选择好的名称。
标记并保留单个 break
您可以使用简单的_Bool
旗帜。假设您包括 stdbool.h
:
bool flag = false;
for(int32_t i = 0; i < 10; i++) {
if (i == number1) {
return_val = 2*number1 + number2;
flag = true;
} else {
number1 += (5 * number2 + 2*number3);
if (i == number2) {
return_val = number1 + (3 * number3);
flag = true;
} else {
number1 += 2 * number3;
if (i == number3) {
return_val = number1 + (2 * number2);
}
}
}
if (flag)
break;
}
请为flag
选择一个更好的名称,理想情况下您应该描述情况。正如你所看到的,我们有一个 break
但我们在易读性方面付出了巨大的代价。
标记并替换 break
与 continue
我们能做什么?替换break
与 continue
并在循环条件中使用该标志:
bool flag = true;
for(int32_t i = 0; flag && i < 10; i++) {
if (i == number1) {
return_val = 2*number1 + number2;
flag = false;
continue;
}
number1 += (5 * number2 + 2*number3);
if (i == number2) {
return_val = number1 + (3 * number3);
flag = false;
continue;
}
number1 += 2 * number3;
if (i == number3) {
return_val = number1 + (2 * number2);
}
}
稍微好一点,但事实是我们没有解决此代码中的主要问题。
将其移至单独的函数
如果此代码片段是更大函数的一部分,那么事实是我们正在解决错误的问题。这不是 break
本身可能会导致问题,但它在更大的上下文中的使用。在 C 中我们没有 std::optional<T>
那么我们可以使用 out 参数(但这不是实现此结果的唯一技术):
for(int32_t i = 0; < 10; i++) {
if (foo(i, &number1, number2, number3, &return_value)) {
break;
}
}
具有类似于我们的第一个实现 flag
的单独函数.
bool foo(int32_t i, int32_t* number1, int32_t* return_val) {
bool has_result = false;
if (i == *number1) {
*return_val = 2 * *number1 + number2;
has_result = true;
} else {
// ...
}
return has_result;
}
更好的是,如果您可以忽略 15.5,那么这个函数将非常容易编写和阅读:
if (i == *number1) {
*return_val = 2 * *number1 + number2;
return true;
}
// ...
别忘了添加 const
在适当情况下。我很确定这可以重构得更好(太多的函数参数、混合值和指针、这两个函数之间的耦合太大),但是由于虚拟名称和缺乏周围的代码,很难提出更好的建议;我想强调的是,将代码移至单独的函数中。
如果分支内的代码足够复杂,那么引入三个独立的函数甚至可能会带来更多好处。什么2 * *number1 + number2
是?它在计算什么?
请随时在 Code Review 上发布您的完整代码(包括周围的代码并使用真实姓名,解释其用途)。
关于c - MISRA C 2012 规则 15.4 用于终止任何迭代语句的break或goto语句不应超过一个,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47741301/