在C中的while循环开关情况

时间:2018-07-29 19:37:34

标签: c while-loop switch-statement

我最近遇到了如下所示的代码片段,我期望它是一个语法错误,但令我惊讶的是,该代码产生了有效的输出。

#include <stdio.h>

int main(void) {
    int x = 2;

    switch(x) {
    case 1: printf("1"); break;

        do {
            case 2: printf("2 "); break;
            case 3: printf("3 "); break;
        } while(++x < 4);

        case 4: printf("4"); break;
    }
    return 0;
}

output: 2 4

编译器: GCC 6.3

我发现了类似的问题,但这并不能完全证明上述条件是合理的, Mixed 'switch' and 'while' in C

任何人都可以解释

  1. 这里到底发生了什么?
  2. 为什么它不是语法错误?
  3. 为什么忽略案例“ 3”?

2 个答案:

答案 0 :(得分:5)

case X: some_statement;labeled statement (6.8.1) ,就像goto_label: some_statement;一样,唯一的警告是case / default标签只能出现在{{1 }}(可能在任意嵌套的复合语句中)。从语法上讲,这使得switch语句仅与case es非常松散耦合。

在语义上,switch可以像计算的switch一样实现,并且像常规的goto一样,它们可能会在任何地方跳跃很多(在C11中,您不能跳过{{ 3}}声明),包括在循环内部(有关其他说明,请参见VLA)。

在您的示例中,goto由于case 3:而被跳过,但是break的确遵循,因为case 4:之后的break是一个循环中断{ {1}},而不是断断续续的case 3:({{1} / break始终适用于它们可以适用的最近的构造)。

答案 1 :(得分:0)

switch语句的正式C语法是:

  

开关 表达式 声明

任何声明可以是带标签的声明,其语法包括:

  

案例 常量表达式 声明

这意味着您可以在switch主体中放入几乎所有内容:它可以是包含多个语句的复合语句以及包含以下内容的do-while语句多个语句和case标签可以添加到任何这些语句的前缀。

编译器仅使用跳转指令(在其抽象机内部;在优化后最终可能会与其他指令一起使用)来实现切换。诸如do-while之类的循环语句是通过测试控制表达式并有条件地跳转的代码实现的。因此,尽管您在结构化语言中想到的是一个不错的结构,但它会归结为跳转指令,并且可以按需将它们交织在一起。

跳跃并不是最令人不安的部分。对象初始化和生存期更加令人关注。如果不小心,switch语句可能会无意间跳过对象的初始化。

永远不会执行“ 3”的printf,因为控制权从switch跳到case 2,然后中断,从而退出了do-while 。这将使代码保留在case 4语句中,该语句显示“ 4”,然后脱离switch语句。