考虑下面的switch语句:

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

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

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


当前回答

另一个例子:如果“default”是一个意外的情况,并且您希望记录错误,但也要做一些合理的事情,那么这可能很有用。示例来自我自己的一些代码:

  switch (style)
  {
  default:
    MSPUB_DEBUG_MSG(("Couldn't match dash style, using solid line.\n"));
  case SOLID:
    return Dash(0, RECT_DOT);
  case DASH_SYS:
  {
    Dash ret(shapeLineWidth, dotStyle);
    ret.m_dots.push_back(Dot(1, 3 * shapeLineWidth));
    return ret;
  }
  // more cases follow
  }

其他回答

这是合理的,但相当令人讨厌。我的建议是,允许出现漏洞通常是不好的,因为它会导致一些非常混乱的意大利面条代码。

将这些情况分解成几个switch语句或更小的函数几乎肯定更好。

@Tristopia:你的例子:

Example from UCS-2 to UTF-8 conversion 

r is the destination array, 
wc is the input wchar_t  

switch(utf8_length) 
{ 
    /* Note: code falls through cases! */ 
    case 3: r[2] = 0x80 | (wc & 0x3f); wc >>= 6; wc |= 0x800; 
    case 2: r[1] = 0x80 | (wc & 0x3f); wc >>= 6; wc |= 0x0c0; 
    case 1: r[0] = wc;
}

(我认为)如果它是这样写的,它的意图会更清楚:

if( utf8_length >= 1 )
{
    r[0] = wc;

    if( utf8_length >= 2 )
    {
        r[1] = 0x80 | (wc & 0x3f); wc >>= 6; wc |= 0x0c0; 

        if( utf8_length == 3 )
        {
            r[2] = 0x80 | (wc & 0x3f); wc >>= 6; wc |= 0x800; 
        }
    }
}   

[edit2] @Tristopia:你的第二个例子可能是follow-through用法最清晰的例子:

for(i=0; s[i]; i++)
{
    switch(s[i])
    {
    case '"': 
    case '\'': 
    case '\\': 
        d[dlen++] = '\\'; 
        /* fall through */ 
    default: 
        d[dlen++] = s[i]; 
    } 
}

..但就我个人而言,我会把评论识别分解成它自己的功能:

bool isComment(char charInQuestion)
{   
    bool charIsComment = false;
    switch(charInQuestion)
    {
    case '"': 
    case '\'': 
    case '\\': 
        charIsComment = true; 
    default: 
        charIsComment = false; 
    } 
    return charIsComment;
}

for(i=0; s[i]; i++)
{
    if( isComment(s[i]) )
    {
        d[dlen++] = '\\'; 
    }
    d[dlen++] = s[i]; 
}

默认条件可以是开关中case子句可以存在的任何位置。它不需要是最后一个子句。我曾见过将默认值作为第一个子句的代码。情况2:正常执行,即使默认子句在它上面。

作为测试,我把示例代码放在一个名为test(int value){}的函数中,并运行:

  printf("0=%d\n", test(0));
  printf("1=%d\n", test(1));
  printf("2=%d\n", test(2));
  printf("3=%d\n", test(3));
  printf("4=%d\n", test(4));

输出结果为:

0=2
1=1
2=4
3=8
4=10

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);
  }
}

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

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),你的案例非常长,所以你不想在默认的底部重复整个案例代码,这非常有用。