考虑以下switch语句:
switch
switch( value ) { case 1: return 1; default: value++; // fall-through case 2: return value * 2; }
此代码可以编译,但对于 C90/C99 是否有效(= 定义的行为)?我从未见过 默认 情况不是最后一种情况的代码。
编辑: 正如 Jon Cage 和 KillianDS 所写:这真的是丑陋和令人困惑的代码,我很清楚这一点。我只对一般语法(是否已定义?)和预期输出感兴趣。
C99 标准对此没有明确说明,但综合所有事实,它是完全有效的。
Acase和defaultlabel 等价于一个goto标签。请参见 6.8.1 标记语句。特别有趣的是 6.8.1.4,它启用了已经提到的 Duff 设备:
case
default
goto
任何语句前面都可以有一个前缀,将标识符声明为标签名称。标签本身不会改变控制流,控制流在它们之间继续畅通无阻。
编辑 :开关中的代码没什么特别的;它是一个普通的代码块,就像在- 语句中if一样,带有额外的跳转标签。这解释了失败行为以及为什么break是必要的。
if
break
6.8.4.2.7 甚至给出了一个例子:
switch (expr) { int i = 4; f(i); case 0: i=17; /*falls through into default code */ default: printf("%d\n", i); }
在人工程序片段中,标识符为 i 的对象具有自动存储持续时间(在块内)但从未初始化,因此如果控制表达式具有非零值,则对 printf 函数的调用将访问一个不确定的值。同样,无法调用函数 f。
case 常量在 switch 语句中必须是唯一的:
6.8.4.2.3 每个case标签的表达式应为整数常量表达式,同一switch语句中的任何两个case常量表达式转换后的值不得相同。switch 语句中最多可以有一个默认标签。
评估所有案例,然后跳转到默认标签,如果给出:
6.8.4.2.5 整数提升在控制表达式上执行。每个 case 标签中的常量表达式都转换为控制表达式的提升类型。如果转换后的值与提升的控制表达式的值匹配,则控制跳转到匹配的 case 标签后面的语句。否则,如果有默认标签,则控制跳转到有标签的语句。如果没有转换后的 case 常量表达式匹配并且没有默认标签,则不会执行 switch 主体的任何部分。