C 替代“while(1)”简化分支
有时,我会使用C 替代“while(1)”简化分支,c,C,有时,我会使用while(1)块来展平一系列的if..else不成比例。它沿着这些路线走 而不是做: // process if (success) { // process if (success) { //process if (success) { // etc } } } 我有: 我对结尾的隐式跳转感到有点恼火,而。我可以用一个更精简的结构(即在结尾处不使用break)吗 我可以用一个变量(或寄存器?)交换最后的break。这并不是更
while(1)
块来展平一系列的if..else
不成比例。它沿着这些路线走
而不是做:
// process
if (success) {
// process
if (success) {
//process
if (success) {
// etc
}
}
}
我有:
我对结尾的隐式跳转感到有点恼火,而。我可以用一个更精简的结构(即在结尾处不使用break
)吗
我可以用一个变量(或寄存器?)交换最后的break
。这并不是更精简或更清晰
int once = 1;
while (once--) {
// process
if (!success) break;
// process
if (!success) break;
// process
if (!success) break;
// etc
}
for循环看起来会更好一些(C99):
我想用一个开关盒。它看起来并没有好多少,尽管它会起作用
switch (1) { default:
// process
if (!success) break;
// process
if (!success) break;
// process
if (!success) break;
// etc
}
在这种情况下,标签的概念似乎是无与伦比的
// process
if (!success) goto end;
// process
if (!success) goto end;
// process
if (!success) goto end;
// etc
end:
你们还知道/使用了什么方法?以下是一种与循环非常类似的方法,但不需要在末尾使用计数器或break
语句
do
{
// process
if (!success) break;
// process
if (!success) break;
// process
if (!success) break;
...
// No need for a break statement here
}
while(0);
不清楚你为什么需要筑巢或休息。当序列在第一次失败时需要跳转时,我总是这样做:
// process
if (success) {
// more process
}
if (success) {
// still more process
}
if (success) {
// even more process
}
摆弄比特提供了一种常见的方法。另一种常见的方法是使用单个状态变量/标志来实现类似的结果
bool bErr = false;
if (!bErr && success) {
// do something
} else {
bErr = true;
}
if (!bErr && success2) {
// do something
} else {
bErr = true;
}
if (bErr) {
// hanlde cleanup from errors
}
你们还知道/使用什么方法
您可以将while
循环封装在一个函数中(并在使用while
循环的地方调用此函数):
任何编译器(例如,即使禁用了优化的gcc
)都将内联静态
函数(如果调用一次)。(当然,一些变量可能必须在process
函数的词法范围内,在这种情况下,只需将它们作为函数的参数提供即可)
请注意,从上到下而不是水平地编写代码(例如,使用嵌套的if
)的示例称为duffing。这里有一篇关于这个主题的好文章:
此外,在中还有针对水平代码的特定警告:
如果您需要3级以上的缩进,那么无论如何都会出错,应该修复您的程序
如果将生成success
的每个条件块的主体安排为如下函数,或者可以将每个//进程
简化为布尔表达式,例如:
success = f1() ;
if( success )
{
success = f2() ;
if( success )
{
success = f3() ;
if( success )
{
success = f4()
}
}
}
然后,您可以利用短路计算将其简化为单个布尔表达式:
success = f1() &&
f2() &&
f3() &&
f4() ;
如果f1()
返回false并且每次后续调用都返回false,则不会调用f2()
,表达式求值将在第一个&
操作数子表达式上中止以返回false。另一个选项将使用简单的标志变量
bool okay = true;
if(okay &= success){
// process
}
if(okay &= success){
// process
}
if(okay &= success){
// process
}
而像这样的循环是避免goto
的奇怪方法<代码>转到
可以并且应该用于O.P.提到的情况。这是无限转到;break的目标定义明确且不可变。有了goto,你可以有任意数量的目标——break的限制性加强了结构。我可以想象复制和粘贴一块代码,例如忽略更改标签名称。@FiddlingBits人们被教导不要使用goto
,因为这会导致复杂和混乱的代码。在这种特殊情况下,您实际上是通过使用do/while
来复制goto
的自然功能。如果不熟悉代码的人开始查看代码,他们将不知道为什么会有循环,直到他们遇到while(0)
。它并没有立即传达代码应该做什么。@PavanYalamanchili:说得好,它至少应该得到一个明确的评论——对于可怜的(通常是缺乏经验的)维护人员来说!对goto的憎恨源于Dijkstra试图强迫结构化编程进入一个不想要它的世界。不使用goto不是“良好实践”;这是一个断章取义的40年历史的无关事件。OP的用例实际上是goto的标准用法——它是正确的语言特性:生成更干净、更简单、更快的代码。您可以将if语句更改为if(!(bErr |=!success)){…}
(或类似的内容),并放弃对那些冗长的else语句的任何需要(我的意见)@Sergeelse
语句的要点是设置错误标志。这一点是,如果任何单个块失败,就会设置错误标志,并且不再执行其他块。在我的示例中,每当成功为false时,bErr标志就会设置为true,或者即使成功为true,也会保持设置为true,并强制if语句失败。相同的想法,不同的实现。但是,是的,我知道有些人不喜欢在if语句中使用赋值运算符。@Serge是的,你应该真正避免在求值(即:if
语句)中使用赋值,因为它可能“短路不存在”(),或者在日志或调试语句中,因为优化器甚至编译时设置(即:ifdef
)可能会阻止分配的发生。当人们知道自己在做什么时(在if
语句场景中),它们不会造成损害。短路应适用于|124;
、和和?
操作符(根据提供的源代码),而不是if
语句本身。不过,这是简洁性与可读性的折衷。+1这也是一个很好的解决方案。不过,也许可以返回一个错误代码,而不是void
。感谢这篇有用的文章。我尝试用谷歌搜索duffing的来源,但没有成功?@PhilippeA。如果你愿意,我认为它来自Duff的设备从未遇到过它,我强烈建议您阅读该页面,并注意到switch语句的奇怪结构,其中嵌入了do while
语句。请参阅@ABFORCE-您真的知道单返回点建议的目的是什么,还是您只是遵循了这个邪教?我喜欢您的解决方案冷逻辑。但是它是n
success = f1() ;
if( success )
{
success = f2() ;
if( success )
{
success = f3() ;
if( success )
{
success = f4()
}
}
}
success = f1() &&
f2() &&
f3() &&
f4() ;
bool okay = true;
if(okay &= success){
// process
}
if(okay &= success){
// process
}
if(okay &= success){
// process
}