我试图在我的代码中摆脱多个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);
}
}
答案 0 :(得分:3)
我认为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上发布您的完整代码(包括周围代码和真实姓名,解释其用途)。
答案 1 :(得分:0)
这是一个相当模糊的算法。在实践中,这通常是许多MISRA规则归结为的,它们阻止你编写奇怪的代码。虽然我无法确切地知道,但它有点像这个代码依赖于各种全局变量,并且可能有更好的方法来编写它。
然而,如果算法与您编写的算法完全相同,并且没有办法解决它,那就是它的本质。在这种情况下,我会用多个return语句重写代码,这违反了另一个(建议)MISRA规则。但是,偏离该规则比反对多次破解/转到更为合理的规则更好。
for(int32_t i = 0; i < 10; i++) {
if (i == number1) {
return 2*number1 + number2;
}
number1 += (5 * number2 + 2*number3);
if (i == number2) {
return number1 + (3 * number3);
}
number1 += 2 * number3;
if (i == number3) {
return number1 + (2 * number2);
}
这比问题中的任何替代方案都更具可读性。
(请注意,您必须u
后缀所有整数常量以符合MISRA标准)