如何从开关内部打破循环?

我正在写一些代码,看起来像这样:

while(true) {
switch(msg->state) {
case MSGTYPE: // ...
break;
// ... more stuff ...
case DONE:
break; // **HERE, I want to break out of the loop itself**
}
}

有什么直接的方法吗?

我知道我可以使用一个标志,通过在切换之后添加一个条件中断来中断循环。我只是想知道 C + + 是否已经有了一些构造。

152891 次浏览

你可以使用 goto

while ( ... ) {
switch( ... ) {
case ...:
goto exit_loop;


}
}
exit_loop: ;

您可能会使用 goto,但是我更喜欢设置一个停止循环的标志。然后打开开关。

AFAIK 在 C + + 中没有“双重中断”或类似的结构。最接近的应该是 goto——尽管它的名字有一个糟糕的内涵,存在于这种语言中是有原因的——只要它被谨慎和节约地使用,它就是一个可行的选择。

完成这项工作的一个简洁的方法是将其放入一个函数中:

int yourfunc() {


while(true) {


switch(msg->state) {
case MSGTYPE: // ...
break;
// ... more stuff ...
case DONE:
return;
}


}
}

可选的(但是“坏习惯”) : 正如已经建议的那样,您可以使用 goto,或者在开关内部抛出一个异常。

在这种情况下,没有用于打破循环的 C + + 构造。

要么使用一个标志来中断循环,要么(如果合适的话)将代码提取到函数中并使用 return

前提

无论使用什么语言或者需要什么功能,下面的代码都应该被认为是不好的形式:

while( true ) {
}

支持论点

while( true )循环的形式很糟糕,因为它:

  • 打破 while 循环的隐含契约。
    • While 循环声明应该显式地声明 只有退出条件。
  • 意味着它会永远循环下去。
    • 必须读取循环中的代码才能理解终止子句。
    • 永远重复的循环阻止用户从程序内终止程序。
  • 效率低下。
    • 有多个循环终止条件,包括检查“ true”。
  • 很容易被窃听。
    • 不能轻易确定将始终在每次迭代中执行的代码放在何处。
  • 导致不必要的复杂代码。
  • 自动源代码分析。
    • 为了发现错误、程序复杂性分析、安全检查,或者在不执行代码的情况下自动获得任何其他源代码行为,指定初始中断条件允许算法确定有用的不变量,从而改进自动源代码分析指标。
  • 无限循环。
    • 如果每个人总是使用 while(true)来表示不是无限的循环,那么当循环实际上没有终止条件时,我们就失去了简明通信的能力。(可以说,这种情况已经发生,因此这个问题毫无意义。)

“去”的另一种选择

下面的代码是更好的形式:

while( isValidState() ) {
execute();
}


bool isValidState() {
return msg->state != DONE;
}

好处

没有标志。没有 goto。没有例外。易于改变。易于阅读。易于修复。另外代码:

  1. 将循环工作负载的知识与循环本身隔离开来。
  2. 允许维护代码的人轻松地扩展功能。
  3. 允许在一个地方分配多个终止条件。
  4. 将终止子句与要执行的代码分开。
  5. 对核电站更安全。 ; -)

第二点很重要。在不知道代码如何工作的情况下,如果有人要求我让主循环让其他线程(或进程)有一些 CPU 时间,我会想到两种解决方案:

选择一

轻松插入暂停:

while( isValidState() ) {
execute();
sleep();
}

选项二

重写执行:

void execute() {
super->execute();
sleep();
}

这段代码比嵌入 switch的循环更简单(因此更容易阅读)。isValidState方法应该只确定循环是否应该继续。方法的主力应该被抽象到 execute方法中,它允许子类覆盖默认行为(使用嵌入式 switchgoto是一个困难的任务)。

Python 示例

对比一下 StackOverflow 上发布的以下答案(对于一个 Python 问题) :

  1. 永远循环。
  2. 要求用户输入他们的选择。
  3. 如果用户的输入是“重新启动”,则永远继续循环。
  4. 否则,永远停止循环。
  5. 完。
密码
while True:
choice = raw_input('What do you want? ')


if choice == 'restart':
continue
else:
break


print 'Break!'

反对:

  1. 初始化用户的选择。
  2. 循环,而用户选择的单词是“重新启动”。
  3. 要求用户输入他们的选择。
  4. 完。
密码
choice = 'restart';


while choice == 'restart':
choice = raw_input('What do you want? ')


print 'Break!'

在这里,while True会导致误导和过于复杂的代码。

即使您不喜欢 goto,也不要使用异常退出循环。下面的例子展示了它可能有多丑陋:

try {
while ( ... ) {
switch( ... ) {
case ...:
throw 777; // I'm afraid of goto
}
}
}
catch ( int )
{
}

我会使用 goto作为在 这个答案。在这种情况下,goto将使代码比任何其他选项都更加清晰。我希望 这个的问题会有所帮助。

但是我认为使用 goto是这里唯一的选择,因为字符串 while(true)。您应该考虑对循环进行重构。我认为解决办法如下:

bool end_loop = false;
while ( !end_loop ) {
switch( msg->state ) {
case MSGTYPE: // ...
break;
// ... more stuff ...
case DONE:
end_loop = true; break;
}
}

或者甚至是下面这些:

while ( msg->state != DONE ) {
switch( msg->state ) {
case MSGTYPE: // ...
break;
// ... more stuff ...
}

你可以把你的开关放到一个单独的函数中,像这样:

bool myswitchfunction()
{
switch(msg->state) {
case MSGTYPE: // ...
break;
// ... more stuff ...
case DONE:
return false; // **HERE, I want to break out of the loop itself**
}
return true;
}


while(myswitchfunction())
;

另一种解决方案是将关键字 continuebreak结合使用,即:

for (;;) {
switch(msg->state) {
case MSGTYPE:
// code
continue; // continue with loop
case DONE:
break;
}
break;
}

使用 continue语句完成希望循环继续的每个大小写标签,并使用 break语句完成应终止循环的大小写标签。

当然,这个解决方案只有在 switch 语句之后没有其他代码要执行的情况下才有效。

如果我对 C + + 语法记得很清楚,就可以像对 goto一样,为 break语句添加一个标签。所以你想要的很容易写出来:

while(true) {
switch(msg->state) {
case MSGTYPE: // ...
break;
// ... more stuff ...
case DONE:
break outofloop; // **HERE, I want to break out of the loop itself**
}
}


outofloop:
// rest of your code here

最简单的方法是在切换之前放一个简单的 IF,这个 IF 测试您退出循环的条件... ... 。再简单不过了

C + + 中的 break关键字仅终止最嵌套的封闭迭代或 switch语句。因此,您不能直接在 switch语句中跳出 while (true)循环; 但是您可以使用以下代码,我认为这是解决此类问题的一个很好的模式:

for (; msg->state != DONE; msg = next_message()) {
switch (msg->state) {
case MSGTYPE:
//...
break;


//...
}
}

如果您需要在 msg->state等于 DONE时执行某些操作(例如运行一个清理例程) ,那么将该代码立即放在 for循环之后; 也就是说,如果您当前有:

while (true) {
switch (msg->state) {
case MSGTYPE:
//...
break;


//...


case DONE:
do_cleanup();
break;
}


if (msg->state == DONE)
break;


msg = next_message();
}

然后使用:

for (; msg->state != DONE; msg = next_message()) {
switch (msg->state) {
case MSGTYPE:
//...
break;


//...
}
}


assert(msg->state == DONE);
do_cleanup();

考虑到解释的深度,我很惊讶这么简单... 这就是你需要的..。

bool imLoopin = true;


while(imLoopin) {


switch(msg->state) {


case MSGTYPE: // ...
break;


// ... more stuff ...


case DONE:
imLoopin = false;
break;


}


}

哈哈! ! 真的! 这就是你所需要的! 一个额外的变量!

while(MyCondition) {
switch(msg->state) {
case MSGTYPE: // ...
break;
// ... more stuff ...
case DONE:
MyCondition=false; // just add this code and you will be out of loop.
break; // **HERE, you want to break out of the loop itself**
}
}
  while(true)
{
switch(x)
{
case 1:
{
break;
}
break;
case 2:
//some code here
break;
default:
//some code here
}
}

为什么不直接修复 while 循环中的条件,导致问题消失?

while(msg->state != DONE)
{
switch(msg->state) {
case MSGTYPE: // ...
break;
// ... more stuff ...
case DONE:
// We can't get here, but for completeness we list it.
break; // **HERE, I want to break out of the loop itself**
}
}

我想

while(msg->state != mExit)
{
switch(msg->state)
{
case MSGTYPE: // ...
break;
case DONE:
//  ..
//  ..
msg->state =mExit;
break;
}
}
if (msg->state ==mExit)
msg->state =DONE;

我遇到了同样的问题,用一面旗子解决了。

bool flag = false;
while(true) {
switch(msg->state) {
case MSGTYPE: // ...
break;
// ... more stuff ...
case DONE:
flag = true; // **HERE, I want to break out of the loop itself**
}
if(flag) break;
}

不,C + + 没有这样的结构,因为关键字“ break”已经为退出开关块保留了。也可以选择做。.带有退出标志的 while ()就足够了。

do {
switch(option){
case 1: ..; break;
...
case n: .. ;break;
default: flag = false; break;
}
} while(flag);

因为 switch使用 breakswitch(而不是从 while(1))突破,所以它需要 goto语句:

while(1) {
switch (*p) {
case ' ':
p++;
break;
case '\n':
p++; *s=p; return(i);
case '\0':
*s=p; return(i);
default:
token[i]=p;
i++;
p++;
goto ex1;
};
};
ex1:

我不能给同一行添加多个案例,比如:

大小写:

是的

大小写’: 大小写’t:

这就是为什么这里的断口。

看起来最常见的情况应该放在列表的顶部,以使程序运行得更快。 它可能不具有搜索不同案例的并行执行。

可能标准 c 缺少了一些关于这种切换的方法: Https://blog.hackajob.co/better-c-switch-statements-for-a-range-of-values/ = > 允许在开关表达式中使用 < 、 > 、 < = 和 > = 运算符

我认为它应该是(如果 c 语言语法改变了)这样的:

switch (c) {
case >= 5:
... op1
endcase;
case == 1:
case == 3:
... op2
endcase;
default:
...
};

当 c 等于1或3时执行 op2,当 c 大于或等于5时执行 op1。 因为比较等于或大于或小于将很容易以类似的方式发生。

  while(1) {
switch (c) {
case >= 2:
... op1
case <= 5:
... op2
break;
default:
...
};
};

这种情况下 op1对 c 大于2执行,op2对2 < = c < = 5执行,中断从 while-loop 退出。