9

可能是重复的,但找不到相同的。

假设我有以下C代码:

int a;
printf("Enter number :");
scanf("%d",&a);  // suppose entered only an integer
                // ignoring return value of scanf()

我有一个案例来检查azero还是non-zero

if(a)
  printf("%d is non-zero",a);
else
  printf("%d is zero",a);

一切都很好if-else,我也知道if-else实现这一点的其他变体。但是问题来了,switch-case因为它说我们可以实现switch-case我们可以做的一切if-else。但是下面的代码失败了。

switch(a)
{
 case a:
       printf("%d is non-zero",a);
       break;
 default:
       printf("%d is zero",a);
       break;
}

我也知道在上面的代码中扭转这种情况,如下所示,我会得到我的答案。

switch(a)
{
case 0:
    printf("%d is zero",a);
    break;
default :
    printf("%d is non-zero",a);
    break;
}

但问题是,为什么?为什么if(a)有效而case a:无效?是switch-case编译时操作和if()运行时?

4

6 回答 6

9

原因是switch案例可以实现为跳转表(通常使用无条件分支指令)。所以它们必须在编译时解决。

这使它们比ifs 更快,因此最好尽可能使用它们。

于 2012-12-21T19:00:22.717 回答
2

案例表达式必须是常量。a是一个变量,所以它是不允许的。0是一个常数,所以没关系。只允许常量表达式意味着编译器更容易优化代码。

if 语句的条件表达式没有这样的约束。

于 2012-12-21T18:59:20.097 回答
1

除了编译时/跳转表问题之外,if它们switch也不相同,即使case接受一个变量,这两个代码也不会具有相同的行为。if当且仅当条件表达式产生非零值时才计算 body ,而case当且仅当控制表达式和标签具有相同值时才输入 a 。

和语句之间有很大的区别,请记住s 不是强制性的,如果没有任何东西阻止它,则执行会通过所有 s 。这种行为非常类似于跳转表,因为在执行内部只是跳转到某处并继续直到找到一个. 然而,这种用法很少见,但它可能比版本更有用且更容易操作。if-then-elseswitchbreakcaseswitchbreakif-then-else

该标准要求标签是编译时常量,正如其他人已经说过的,它背后的想法是一个性能跳转表。即使它不是强制性的(C 标准需要灵活),C99 基本原理文档似乎也证实了这一点:

lo .. hi 形式的大小写范围被认真考虑过,但最终没有在标准中采用,理由是它没有增加新功能,只是编码方便有问题。该结构的承诺似乎比它可能被要求提供的更多:

  • 可能会为看似无害的案例范围(例如 0 .. 65535)生成大量代码或跳转表空间。

  • 范围 'A' .. 'Z' 将指定字符代码之间的所有整数“大写 A”和“大写 Z”。在一些常见的字符集中,该范围将包括非字母字符,而在其他字符集中,它可能不包括所有字母字符,尤其是在非英文字符集中。

维基百科有一篇关于跳转表的文章

于 2012-12-21T19:07:09.013 回答
1

正如其他人所说,这是定义语言的方式。

如果你有

int x, y, z;
int a;
... some code calculates x, y, z and a ... 
switch(a)
{
   case x:
      .. do stuff here ... 
      break;
   case y:
      .. some more stuff ...
      break;
   case z:
     ... another bit of code .... 
      break;
}

编译器无法事先确定,在编译时 a 应该是 1、2、3、99、465 还是 5113212。所以这里的代码并不比我们做的效率高

if (a == x) ... do stuff here ... 
else if (a == y) ... some more stuff
else if (a == z) ... another bit of code 

此外,如果 x 和 y 是相同的值怎么办。我们是否希望两者都做一些事情并执行更多的事情,或者只是一个 - 以及哪一个,第一个或第二个。如果编译器重新排序比较,以便它们处于不同的顺序,因为它更有效怎么办?

Switch 主要用于当您有很多选择时,但在构建代码时每个选择都是已知的。如果不是这种情况,你需要别的东西。

于 2012-12-21T19:12:02.250 回答
1

附加信息想分享维基

If the range of input values is identifiably 'small' and has only a few gaps, some compilers that incorporate an optimizer may actually implement the switch statement as a jump table or an array of indexed function pointers instead of a lengthy series of conditional instructions. This allows the switch statement to determine instantly what branch to execute without having to go through a list of comparisons.

于 2012-12-21T19:13:40.440 回答
1

这是语言创建者的设计决定。如果案例标签是常量,编译器可以通过使用跳转表来优化某些案例。如果它们不是,那么代码将等效于多路 if 语句,并且潜在的改进消失了。

用可变的 case 标签定义 switch 语句,甚至为每个分支定义不同的条件是没有问题的,只是 C 的设计者没有这样做。可能是因为他们不认为这是他们编写的代码的优势。

该构造存在于其他语言中,例如我有时使用的 COBOL。有一个退化的版本并不罕见,比如:

EVALUATE TRUE
WHEN x IS EQUAL TO 7
  Do something

WHEN y IS LESS THAN 12 
  Do something else

WHEN z
  Do yet another thing

END-EVALUATE

在这里,我们将if-else if-else链屏蔽为一个开关 (EVALUATE),它通过按顺序评估条件直到它匹配第一个值来工作。

在 C 语言中,设计者不希望这样做,因为它绝对没有提供比链式 if 语句更能获得的性能优势。另一方面,如果我们要求所有条件都是常数......

于 2012-12-21T21:00:06.480 回答