【问题标题】:What are some interesting uses of 'switch' in C/C++? [closed]C/C++ 中“switch”的一些有趣用途是什么? [关闭]
【发布时间】:2014-03-17 09:34:08
【问题描述】:

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 2 中添加了 break 语句。

在我的 C/C++ 编程经验的 3 年(相当小,是的)中,我从未遇到过必须使用 switch 而不放置 break 语句的问题在每个案例中。但从这个功能卡了这么久的事实来看,它可能有一些实用性。

问题:switch 语句有哪些巧妙的用法来利用 C/C++ 中的上述特性?

【问题讨论】:

  • 我不知道你在寻找什么样的聪明用途,但你可以在这篇文章中阅读更多关于为什么switch 需要breakWhy was the switch statement designed to need a break?。如该帖子所述,您可以使用此“功能”进行失败。
  • 存在“问题”,可能需要以相同的方式处理多个值。这对于“问题”非常具体。太宽泛了,IMO。
  • 为什么这个问题主要是基于意见的?我认为这是一个有效的问题!
  • @user3414693 试图找到某种c++ 能力的巧妙用途并不是真正的标准SO 问题。
  • 这确实不是一个标准的 SO 问题,但我不会将其归类为基于意见而不是事实。也许“聪明”这个词会误导,但我要问的只是在编程语言中使用明显的“功能”。是的,我很难将单个答案标记为正确。

标签: c++ c switch-statement


【解决方案1】:

我见过的最有趣的用例之一可能是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 的无堆栈协程非常接近这一点(模邪恶指针 arith)
  • 不幸的是,使用goto(这是switch 归结为)跳入循环可能会使优化器偏离轨道。与 Duff 设备的收益相比,这对性能的不利影响更大。因此,虽然 Duff 的设备在发明时曾经是一个很好的优化,但我不会在新代码中使用它。
【解决方案2】:

这通常在您想对一组值应用类似的操作时使用。例如,以下内容:

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;
   // ... 
}

【讨论】:

    【解决方案3】:

    在我当前的项目中,我有以下枚举:

    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 个月内)会感谢你。

    【讨论】:

      【解决方案4】:

      我经常使用这样的构造来解析命令行参数:

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

      其中参数是枚举类型。

      【讨论】:

      • 我从来没有想过这个,好主意!
      • 啊!是的。我在一个项目中需要这样的东西。谢谢!
      猜你喜欢
      • 2010-09-25
      • 2012-06-18
      • 2012-10-11
      • 2011-07-12
      • 1970-01-01
      • 2011-01-21
      • 2015-06-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多