考虑下面的switch语句:

switch( value )
{
  case 1:
    return 1;
  default:
    value++;
    // fall-through
  case 2:
    return value * 2;
}

此代码编译,但它是有效的(=定义的行为)C90/C99?我从未见过默认情况不是最后一个情况的代码。

编辑: 正如Jon Cage和KillianDS所写的:这真的是丑陋而令人困惑的代码,我很清楚这一点。我只对通用语法(有定义吗?)和预期的输出感兴趣。


当前回答

switch语句中没有定义的顺序。你可以把这些情况看作一个命名标签,一个goto标签。与人们在这里的想法相反,在值2的情况下,默认标签不会跳转到。为了用一个经典的例子来说明,这里是Duff的设备,它是C语言中switch/case的极端代表。

send(to, from, count)
register short *to, *from;
register count;
{
  register n=(count+7)/8;
  switch(count%8){
    case 0: do{ *to = *from++;
    case 7:     *to = *from++;
    case 6:     *to = *from++;
    case 5:     *to = *from++;
    case 4:     *to = *from++;
    case 3:     *to = *from++;
    case 2:     *to = *from++;
    case 1:     *to = *from++;
            }while(--n>0);
  }
}

其他回答

是的,这是有效的,在某些情况下甚至是有用的。一般来说,如果你不需要它,就不要做。

我不知道你是否可以称它为“丑”,当然,在你必须写的情况下,它非常有用:

    switch (cond) {
       case default: Instruction1;
               ...
               InstructionN;
       case 1: FinalInstruction;
    }

您可以避免编写两次代码

在某些情况下,它是有效的,非常有用的。

考虑下面的代码:

switch(poll(fds, 1, 1000000)){
   default:
    // here goes the normal case : some events occured
   break;
   case 0:
    // here goes the timeout case
   break;
   case -1:
     // some error occurred, you have to check errno
}

重点是上面的代码比级联的if更可读,更有效。你可以把default放在最后,但这是毫无意义的,因为它会把你的注意力集中在错误情况上,而不是正常情况上(这里是默认情况)。

实际上,这不是一个很好的例子,在民意调查中你知道最多可能发生多少事件。我真正的观点是,在某些情况下,有一组定义好的输入值,其中有“例外”和正常情况。将异常或正常情况放在前面更好,这是一个选择的问题。

在软件领域,我想到了另一种非常常见的情况:带有一些终端值的递归。如果可以使用开关表示它,默认值将是包含递归调用的常用值和终端值的不同元素(个别情况)。通常不需要关注终端值。

Another reason is that the order of the cases may change the compiled code behavior, and that matters for performances. Most compilers will generate compiled assembly code in the same order as the code appears in the switch. That makes the first case very different from the others: all cases except the first one will involve a jump and that will empty processor pipelines. You may understand it like branch predictor defaulting to running the first appearing case in the switch. If a case if much more common that the others then you have very good reasons to put it as the first case.

阅读评论,这就是为什么最初的海报在阅读英特尔编译器分支循环重组关于代码优化后提出这个问题的具体原因。

然后,它将成为代码可读性和代码性能之间的仲裁。也许最好是写个评论,向将来的读者解释为什么先出现一个案例。

case语句和default语句可以在switch语句中以任意顺序出现。default子句是一个可选子句,如果case语句中的常量都不能匹配,则匹配它。

很好的例子:

switch(5) {
  case 1:
    echo "1";
    break;
  case 2:
  default:
    echo "2, default";
    break;
  case 3;
    echo "3";
    break;
}

输出2,默认值。

如果你想让你的案例在代码中以逻辑顺序呈现(比如,不是说案例1,案例3,案例2/default),你的案例非常长,所以你不想在默认的底部重复整个案例代码,这非常有用。

有些情况下,当您正在将ENUM转换为字符串或将字符串转换为ENUM时,您正在写入/读取文件或从文件中读取文件。

有时需要将其中一个值设为默认值,以弥补手动编辑文件时所犯的错误。

switch(textureMode)
{
case ModeTiled:
default:
    // write to a file "tiled"
    break;

case ModeStretched:
    // write to a file "stretched"
    break;
}