【问题标题】:Incorrect Multiple Cases in Switch not generating compiler error [duplicate]Switch中不正确的多个案例不产生编译器错误[重复]
【发布时间】:2016-02-15 02:44:42
【问题描述】:

我知道此代码不能按“预期”工作。快速看一下这段代码,我们认为返回值应该是1,但是在执行时它返回返回3。

// incorrect
variable = 1;
switch (variable)
{
  case 1, 2:
    return 1;
  case 3, 4:
    return 2;
  default:
    return 3;
}

并且有一些正确的选项可以做到这一点:

// correct 1
variable = 1;
switch (variable)
{
  case 1: case 2:
    return 1;
  case 3: case 4:
    return 2;
  default:
    return 3;
}

// correct 2
switch (variable)
{
  case 1:
  case 2:
    return 1;
  case 3:
  case 4:
    return 2;
  default:
    return 3;
}

Multiple Cases in Switch: 部分回答了这个问题

我想知道为什么不正确的形式编译时没有错误甚至警告(至少在 Borland C++ 编译器中)。

编译器对该代码的理解是什么?

【问题讨论】:

标签: c++


【解决方案1】:

我的猜测是,在第一种情况下,编译器会评估逗号运算符以导致代码执行如下:

switch(variable)
{
  case 2:
    return 1;
  case 4:
    return 2;
  default:
    return 3;
}

从上面可以看出为什么输入 1 返回值 3。我建议你阅读有关逗号运算符的内容。 SO上有一些与它相关的优秀线程。

【讨论】:

  • 我发帖时没有看到你的答案。我觉得有义务投票,因为我们的答案几乎相同:)
  • @MadPhysicist :我很欣赏这个姿态。公共论坛上有礼貌的人越来越少。不过,我回复了这种感觉,因为你应该像我一样得到支持。 :)
  • 为什么投反对票的人?
  • @therainmaker:我没有投反对票,但老实说,我能理解为什么有人会投反对票。在答案中猜测不是一个好主意,在这种情况下,您的猜测也是错误的,因为代码甚至无法使用符合要求的编译器进行编译。
  • @ChristianHackl :“猜测”我的意思不是我可以通过查看代码来判断,但不是通过在 IDE 上运行来验证它。我想它对每个人都有不同的内涵。不过感谢您的评论。我刚看到你来自格拉茨大学。我的一位好奥地利朋友在那里学习。高五:)
【解决方案2】:

做一些实验。

#include <stdio.h>

int test(int variable) {
  switch (variable)
  {
    case 1, 2:
      return 1;
    case 3, 4:
      return 2;
    default:
      return 3;
  }
}

int main(void) {
  int i;

  for (i = 1; i <= 5; i++)
  {
    printf("%d -> %d\n", i, test(i));
  }
  return 0;
}

使用 Borland C++ 5.5.1 for Win32 编译,输出为

1 -> 3
2 -> 1
3 -> 3
4 -> 2
5 -> 3

显示1, 2被解释为23, 4被解释为4

【讨论】:

  • 我们怎么能通过阅读代码立即知道这一点,而不编写测试工具?
【解决方案3】:

a, b 在 C 和 C++ 中都是有效的表达式。它的意思是“评估a,丢弃它,评估b”。表达式的值为b。所以你原来的switch有以下含义:

variable = 1;
switch(variable)
{
  case 2:
    return 1;
  case 4:
    return 2;
  default:
    return 3;
}

有关逗号运算符的更多信息,您可以阅读Wikipedia article

【讨论】:

    【解决方案4】:

    a, b 形式的表达式具有值 b。这就是逗号运算符的工作原理。

    从表面上看,case 1, 2: 等价于 case 2:,以此类推。

    但是,case 标签必须是常量整型表达式,并且1, 2 不是常量表达式,因为它包含逗号运算符(C++ 语法规定常量表达式不能包含逗号操作员)。因此,您的编译器应该会发出错误。

    您会经常看到case 1: case 2:,由于switch后续 行为,这将允许该行之后的语句同时针对1 和2 情况运行.

    【讨论】:

      【解决方案5】:

      快速看一下这段代码,我们认为返回值应该是1,

      我想说,有经验的 C++ 开发人员会立即注意到有问题,并很快得出结论,认为其他程序员不小心尝试使用逗号运算符:,

      但在执行时它返回返回 3。

      不,代码一定不能编译,因为 case 表达式不是常量

      事实上,它不会在任何中途现代编译器中编译。例如,MSVC 2013 说:

      stackoverflow.cpp(8) : error C2051: case expression not constant
      stackoverflow.cpp(10) : error C2051: case expression not constant
      

      1, 2 这样的表达式是逗号运算符的应用,而逗号运算符暗示该表达式不是编译时常量。

      至少在 C++11 和relaxed the rules 出现之前,添加括号,即case (1, 2):将允许编译。它只是不会做你所期望的。

      这在 Switch 的多个案例中得到了部分回答:

      怎么会?其他问题和答案几乎完全是关于 C#,而不是关于 C++。

      我想知道为什么不正确的表单编译没有错误 或事件警告(至少在 Borland C++ 编译器中)。

      因为编译器太老了。最好买一个新的。

      【讨论】:

      • 有人应该向 Borland 提交错误报告 ...
      • @Walter:你为什么不做志愿者? :)
      【解决方案6】:

      在 C 或 C++ 中,逗号表达式有以下规则:

      1. 从左到右操作。
      2. 逗号表达式的值是最后一个表达式的值。

      所以代码case 1,2:等于case 2:,因为逗号表达式的值为2。

      【讨论】:

      • 我真的很惊讶有这么多人在回答之前甚至没有尝试编译代码。
      猜你喜欢
      • 2016-06-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-08-25
      • 2023-03-22
      • 2014-03-15
      相关资源
      最近更新 更多