为什么情况:总是需要常量表达而if()不是?

时间:2012-12-21 18:58:20

标签: c if-statement switch-statement

可能有重复但无法找到相同的内容。

假设我有以下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()运行时?

6 个答案:

答案 0 :(得分:9)

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

这使得它们比if更快,所以最好在可能的情况下使用它们。

答案 1 :(得分:2)

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

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

答案 2 :(得分:1)

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

if-then-elseswitch语句之间存在的区别,请记住break不是强制性的,并且执行属于所有case如果什么都没有阻止它。这种行为与跳转表非常相似,因为在switch执行内部只是在某处跳转并继续直到找到break。但是这种用法很少见,但它比if-then-else版本更有用,也更容易。

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

  

形式的案例范围,lo .. hi,被认真考虑,但最终没有在标准中采用,理由是它没有增加任何新功能,只是编码方便有问题。这个结构似乎承诺的超出了它的强制要求:

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

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

  •   

Wikipedia has an article about jump tables

答案 3 :(得分: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;
}

编译器无法预先弄清楚,在编译的时候应该去,如果它是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主要用于当您有很多选择时,但在构建代码时每个选项都是已知的。如果不是这样,你还需要别的东西。

答案 4 :(得分:1)

其他信息想要分享Wiki

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.

答案 5 :(得分:1)

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

定义带有可变大小写标签的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语句完全没有性能优势。另一方面,如果我们要求所有条件都是常数......