C/C++中'switch'有哪些有趣的用法?

6
在C/C++中,switch语句有一个有趣的特性,即当条件满足时,所有后续的块都将被执行
例如:
int a = 2;
int b = a;
switch(b)
{
     case 1:cout<<1;
     case 2:cout<<2;
     case 3:cout<<3;
     case 4:cout<<4;
};

上述代码将输出234,除非我在第二个case中加入break语句。

在我3年的C/C++编程经验中,我从未遇到过必须在每个case中放置break语句的问题。但是根据这个特性已经存在了很长时间的事实来判断,它可能有一些用途。

问题:有哪些聪明的方法可以利用C/C++中switch语句的上述功能?


3
我不知道你在寻找哪些巧妙的用法,但是你可以阅读这篇文章了解为什么switch语句需要使用breakWhy was the switch statement designed to need a break? 正如该文章所述,你可以利用这一“特性”进行case穿透。 - idanshmu
有些“问题”可能需要以相同的方式处理多个值。这非常特定于该“问题”。在我看来,这太宽泛了。 - Kiril Kirov
为什么这个问题被关闭了,理由是基于个人意见?我认为这是一个合理的问题! - user3414693
1
@user3414693 寻找某种 C++ 能力的聪明用途并不是一个标准的 SO 问题。 - idanshmu
1
这确实不是一个标准的SO问题,但我不会将其归类为基于观点而不是事实。也许“聪明”的词语会引入偏见,但我想问的只是编程语言中一个明显“特性”的用途。 是的,我会很难标记一个答案为正确答案。 - Cheeku
4个回答

7

我看过的最有趣的用例之一可能是达夫设备(Duff's Device),即在一个switch语句中跨多个case扩展作用域的情况,代码可能类似于:

void send( int *to, const int *from, int  count)
{
        int n = (count + 7) / 8;
        switch(count % 8) 
        {
            case 0: do {    *to = *from++;   // <- Scope start
            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);    // <- Scope end
        }
}

Boost Asio的无栈协程非常接近这一点(除了邪恶的指针算术)。 - sehe
3
不幸的是,使用“goto”(也就是“switch”实际上所转化的形式)来跳转到一个循环内部,可能会使优化器失去控制。这可能对性能的影响比Duff's Device带来的收益更为不利。因此,虽然在发明时Duff's Device曾经是一种好的优化方法,但我不会在新代码中使用它。 - cmaster - reinstate monica

6

当您想对一组值应用类似的操作时,通常会使用此功能。例如,以下内容:

switch (event) {
   case DEVICE_DISCONNECTED:
   case CONNECTION_ERROR:
   case CONNECTION_TIMEOUT:
     transitionTo(disconnectedState);
     break;
   case CONNECTION_SUCCESS:
     transitionTo(connectedState);
     break;
}

在我看来,比起下面的写法:

更加简洁易读:

switch (event) {
   case DEVICE_DISCONNECTED:
     transitionTo(disconnectedState);
     break;
   case CONNECTION_ERROR:
      transitionTo(disconnectedState);
     break;
   case CONNECTION_TIMEOUT:
     transitionTo(disconnectedState);
     break;
   // ... 
}

6
在我的当前项目中,我有以下枚举:
enum NodeType
{
  SCALAR, COMPOSITE, ARRAY, RESTRICTED_ARRAY
};

因此,相当多的节点处理程序使用此模式:
switch (nodeType)
{
  case SCALAR:
    processScalar();
    break;
  case COMPOSITE:
    processComposite();
    break;
  case RESTRICTED_ARRAY:
    if (!handleRestrictions())
      return false;
    // continue to next case
  case ARRAY:
    processArray();
    break;
}

请注意,几乎必须用注释(就像我上面所做的那样)明确表示缺少break是有意的 - 未来的维护人员(包括您在3个月后)将感谢您。

5

我经常使用以下结构来解析命令行参数:

switch (argument) {
    case arg_h:
    case arg__help:
    case arg_questionmark:
        printf("Help\n");
        break;
    case arg_f:
    case arg__file:
        //...
}

其中argument是一个枚举类型。


2
我从未想过这个,很酷的想法! - Tyler Jandreau
啊!是的。我在一个项目中需要这样的东西。谢谢! - Cheeku

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接