【问题标题】:What does comma operator mean in a switch statement?switch 语句中的逗号运算符是什么意思?
【发布时间】:2013-10-19 14:03:36
【问题描述】:

我被问到一个问题,并被要求提供输出。

int main(void){  
    int x = 2;  
    switch(x){  
        case 1,2,1: printf("Case 1 is executed");  
            break;  
        case 2,3,1: printf("Case 2 is executed");  
            break;  
        default : printf("Default case us executed");  
    }  
    return 0;  
}

上面的代码在 Turbo C 中给出了“Case 1 is executed”的输出,但是在代码块和在线编译上,它给出了编译器错误。

哪一个是正确的?是不是编译器错误?如果不是,为什么代码只能在 Turbo C 上运行?

【问题讨论】:

  • 这看起来很奇怪。我有预感 turbo C 可能会首先评估这些案例comma operator
  • @RageD 这也无法解释:1,2,12,3,1 通常评估为相同的值,所以我仍然希望 Turbo C 给出如果这是原因,编译器错误。
  • @hvd 好点——无论如何,它仍然模棱两可。即使在下面的答案中,也不应该允许,因为案例枚举仍然会提供重复项。
  • 我的编译器完全按照 RageD 所说的做。它只计算 1,2,1 中的 1,然后抱怨在该数字后面没有看到冒号 (:)。
  • 使用 Turbo C++ 3.0 进行测试表明它给出了编译器错误:imgur.com/KsIy2ja

标签: c++ c


【解决方案1】:

是否是编译器错误。

代码在两种语言中都无效:case 表达式必须是常量表达式,并且常量表达式不能包含逗号运算符。 (在 C 中,这是明确说明的;在 C++ 中,您必须取消选择语法才能发现 constant-expression 必须是 conditional-expression,而不能包含一个逗号)。

即使您被允许在此处使用逗号运算符,switch 语句仍然无效,因为两种情况都具有相同的值 1。

如果不是,为什么代码只能在 Turbo C 上运行。

因为自上次更新史前编译器以来,这两种语言都发生了显着变化。如果您想学习本世纪的 C 或 C++ 变体,请不要使用它。

【讨论】:

  • 同意@Mike - 如果您使用 Code::Blocks,minGW 是一个维护良好的开源编译器,免费提供。这将是比 Turbo C 更好的选择。
  • 本世纪唯一的 C 形式变体是 C11。并非所有“现代”编译器都支持 C99。
  • 引用a comment on another turbo-c question提示,使用gcc
  • @KeithThompson:对不起,当问题被标记为“C”时,我一直忘记不要讽刺。
  • 允许编译器实现不影响符合程序的扩展,每个编译器都会这样做;所以 Turbo C 允许这样做的事实不应该被认为是 Turbo C 的一个小问题
【解决方案2】:

switch 语句中的逗号运算符是什么意思?
这意味着你有一个旧的编译器。

编辑帖子(显示case range示例)

前两个示例(包括您的原始代码)显示了不正确的 switch 语句语法(带有解释)。第三个代码示例展示了如何正确堆叠大小写标签:

在您的代码中,编译器应该在case 1, 之后标记了第一个逗号

#include <ansi_c.h>
int main(void){  
    int x = 2;  
    switch(x)
    {  
        case 1,2,1: printf("Case 1 is executed");  
        break;  //error flagged at first comma, and all comma after in case
        case 2,3,1: printf("Case 2 is executed");  
        break;  
        default : printf("Default case is executed");  
    }  
    return 0;  
}  

而且,即使这样修改,您也应该得到重复标签错误:

#include <ansi_c.h>
int main(void){  
    int x = 2;  
    switch(x)
    {  
        case 1:
        case 2:
        case 1: printf("Case 1 is executed"); //duplicate label 1 error. (and others below) 
            break;  
        case 2:
        case 3:
        case 1: printf("Case 2 is executed");  
            break;

        default : printf("Default case is executed");  
    }
    return 0;  
}

这个例子是完全合法的(C99, C11) 并且很有用:即没有重复的标签,并且语法通过堆叠unique标签符合正确的开关用法处理case 1: OR case 2: OR case 3: 应以相同方式处理的情况(在同一块中)。当然,案例 4、5 和 6 也是如此。

#include <ansi_c.h>
int main(void){  
    int x = 2;  
    switch(x)
    {  
        case 1:
        case 2:
        case 3: printf("Case 1,2 or 3 is executed"); //duplicate label 1 error. (and others below) 
            break;  
        case 4:
        case 5:
        case 6: printf("Case 4,5 or 6 is executed");  
            break;
    }
    getchar();
    return 0;  
}

最后一个例子只是为了完整性。它说明了case range 表达式。虽然引起了 C 程序员的兴趣,但它还不是 C99 或 C11 的一部分,而是 Sun (a flavor of unix)GNU C compiler 的扩展(等)

...
    switch(x)
    {  
            case 'a' ... 'z':  //note: spaces between all characters ('a') and ellipses are required
                    printf("lowercase alpha char detected");
                    break;
            case 'A' ... 'B':
                    printf("uppercase alpha char detected");
                    break;

            default: printf("Default case is executed");  
    }
...

您看到从一个编译器到另一个编译器的结果模棱两可的原因可能是 Turbo C 真的真的老了。您正在使用的版本可能是针对不再适用的 C 标准版本实施的。

考虑更改为当前的编译器。 MinGW 是一种廉价(免费)的替代方案。 MinGW 是一个维护良好的开源编译器。如果您喜欢使用集成开发环境 (IDE),Code::Blocks 是一个选项,也是免费的,并且作为选项与 MinGW 捆绑在一起。

关于兼容性,请在此链接中搜索 Comparison to Other Compiler Suites 以阅读有关 MinGW 扩展的信息。 MinGW 扩展在扩展功能的同时,有时会使使用它们编写的代码与其他当前 编译器不可移植。建议在使用时谨慎使用。

【讨论】:

    【解决方案3】:

    Turbo C 在 switch case 上使用逗号运算符并取最后一个值,例如 case 1, 2, 3: 将被编译为 case 3: case 2, 3, 1 as case 1: 因此 Turbo C 不会给你任何错误。其他编译器不允许您使用 case 1, 2, 3: kind of statement 本身。

    但在你的情况下,即使 Turbo c 也会出错,因为 case 语句是这样的 case 1, 2, 1: 和 case 3, 2, 1: 这将被编译为 case 1: 和 case 1: 因此根据 switch case 规则,你只能有一个带有值的 case,你不能重复这个 case

    我更喜欢使用 gcc 编译器而不是 Turbo C

    【讨论】:

      【解决方案4】:

      您不能使用两次相同的“大小写”值
      这是不正确的:case 1: case 2: case 1: printf("Case 1 is executed");
      尝试在 VS2010 上编译 =>(错误 C2196:case value '1' already used)

      【讨论】:

      • 不,你不能,但这不相关。问题中的代码是case 1, 2, 1:(这是非法的,因为在该上下文中不允许使用逗号运算符),而不是case 1: case 2: case 1:
      【解决方案5】:

      是否是编译器错误。

      这会导致编译错误(不知道TURBO C++,但在现代编译器中)。
      这不是 switch 语句的工作方式(c/c++ 中的语法无效)。您不能在switch 语句中重用case 值(参见chris 给出的link) 可以这样做;

       switch(x){
                  case 1: case 2: case 3: printf("Case 1 is executed");
                  break;
                  default : printf("Default case us execyted"); 
                }
      

      【讨论】:

      • @chris;哎呀!我忘记了。
      • @hacks 但你还是没有回答问题。
      • @hacks - 我不是反对者之一,但您是否看到您的声明 It is not a compiler error but it will cause a compilation error 可能会让还不熟悉调试术语的人感到困惑?只是提供一个可能的为什么
      • @ryyker; :)。是的。我现在正在意识到。我认为最好删除该行。
      • @downvoter;在编辑(更正)答案后不删除反对票是一种非常糟糕的做法。
      【解决方案6】:

      仅供参考,今天人们可以在适当的时候(不经常)使用GCC case ranges extension 来获得类似的结果(仅支持范围,而不是任意的值列表)。

      case 1 ... 5:
      case 'A' ... 'Z':
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-11-01
        • 2019-09-29
        • 1970-01-01
        • 1970-01-01
        • 2013-05-07
        • 2015-04-05
        • 2015-09-18
        相关资源
        最近更新 更多