【问题标题】:Final clause in C switch statement (possibly using goto)C switch 语句中的最后一个子句(可能使用 goto)
【发布时间】:2011-08-04 09:02:31
【问题描述】:

我可以在 C 开关中使用类似 javas finally 子句的东西。我的大多数案例都有一组共享的功能,我想把它们放在一个案例中。我正在考虑使用 goto 语句来实现这一点,非常了解 goto 代码混淆能力,将共享案例放在 switch 语句的底部似乎仍然是一种“更干净”的方式来做到这一点,而不是将共享功能划分为单独的功能。

无论如何,我一直在尝试这样做:

switch( x ) {
case 0:
    printf("Case 0\n");
    goto case 2;
    break;
case 1:
    printf("Case 1\n");
    goto case 2;
    break;
case 2:
    printf("Case 2\n");
    break;
default:
    // do nothing
    break;
}

但是,使用 gcc,失败并出现错误

error: expected identifier or ‘*’ before ‘case’

关于如何使它工作的任何建议?或者可能是更好的方法?

【问题讨论】:

    标签: c switch-statement goto


    【解决方案1】:

    “最佳实践”当然是将共享代码委托给函数。但在某些情况下,这是过度设计,或者根本不可能/不可取,那么您可以这样做:

    switch( x ) 
    {
    case 0:
        printf("Case 0\n");
        goto shared_material;
    
    case 1:
        printf("Case 1\n");
        goto shared_material; // Unnecessary, but keep it for clarity.
    
    case 2:
    shared_material:
        printf("Case 2\n");
        break;
    
    default:
        // Write a meaningful error message somewhere
        return -1;
    }
    

    我不觉得这太难读了,我也没有任何问题,只要整个语句都适合一个屏幕(否则它就符合意大利面条代码 em>)。但是,您可能不得不在代码审查中为它辩护,这是我将放弃此类结构并重新考虑代码的主要原因之一。

    【讨论】:

    • 好吧,这行得通。我只是认为 case 语句是 switch 语句内部的标签。
    • @Kenneth:不在 C 中。它们在 C# 中(可能在 Java 中),因为 C# 不允许您通过 case 语句,所以您使用 goto where in C 你会使用// fall through 评论。
    • 在内部,在生成的代码中,它们的行为类似于标签,但在 C 中,从语法上讲,它们不是。
    • 我同意这个解决方案和你的评论!如果共享代码很大,那么它应该有自己的功能。在我的情况下,总共享代码是四行(使用两个局部变量)并且添加一个函数似乎......那么杂乱的代码,分散的代码的对立面是什么?
    • @Karl:过度工程:当清理代码有两行长,并且涉及多个局部变量时。不可取:当分析显示额外的函数调用会损害性能时。另外,请参阅我对 Johan 回答的评论:如果您使用清理功能,则会出现代码重复问题。只要整个 switch 语句适合一个屏幕(这样你就可以一眼看出指令流是什么),这种方法是可以的。
    【解决方案2】:

    为什么不把通用代码放在开关之后?

    我觉得我必须更新这个回复,用我认为设计更好的答案来解释接受的答案:

    switch( x )
    {
        case 0:
            printf("Case 0\n");
            break;
    
        case 1:
            printf("Case 1\n");
            break;
    
        case 2:
            break;
    
        default:
            return -1; 
    }
    
    printf("Common code for cases 0, 1 and 2\n");
    

    或者,如果您出于某种原因不想将其分解为单独的函数,您当然可以在“默认”情况下设置一个标志,以阻止公共代码执行。

    【讨论】:

    • 我忘了说只有某些情况需要共享该代码。
    • 那么它不像javas' finally ;-) 也更新了我的答案以表明我的意思
    • 是的。 finally 也仅适用于异常。也许应该改写原来的问题。
    • ...其实不是,最后看Java教程 ;-) (download.oracle.com/javase/tutorial/essential/exceptions/…)
    【解决方案3】:

    您可以使用标志do2,根据需要设置它并在切换后检查它。

    如果它具有许多层次依赖关系更复杂,则构建具有转换的状态机。

    【讨论】:

      【解决方案4】:

      我宁愿采用这种方法:

      void sharedFunction() {
          printf("Case 2\n");
      }
      
      switch( x ) {
      case 0:
          printf("Case 0\n");
          sharedFunction();
          break;
      case 1:
          printf("Case 1\n");
          sharedFunction();
          break;
      case 2:
          sharedFunction();
          break;
      default:
          // do nothing
          break;
      }
      

      【讨论】:

      • 我知道这是执行此操作的“正确方法”,但这对我来说似乎很混乱,因为在这种情况下共享代码不过是几行代码。
      • 函数的长度没有限制。 :)
      • @Kenneth:我也不喜欢。当您想添加依赖于局部变量的共享内容时,您必须向 sharedFunction 添加一个参数,从而在 3 个不同的地方更改代码。 goto 方法在这方面更胜一筹。干净的解决方案应尽可能远离switch 构造。
      【解决方案5】:

      以下作品:

      switch( x ) {
      case 0:
          printf("Case 0\n");
          if(0)
      case 1:{
          printf("Case 1\n");
          }
      case 2:
          printf("Case 2\n");
          break;
      default:
          // do nothing
          break;
      }
      

      【讨论】:

      • 我印象深刻。我永远不会想出这个,我也不愿意维护包含这个的代码,但我仍然印象深刻。
      • @Kenneth,将所有case 语句包装在{} 中是一种很好的做法(在这里您应该将所有这些语句都包装在{} 中)。我正在做的只是放一个if(0)。至少避免使用goto。
      • 但是这个解决方案只适用于单个 case 语句。
      • @Kenneth,它将普遍适用;我在这里写了您在问题中发布的内容。您可以随意扩展。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-07
      • 2010-10-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多