Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/66.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 为什么案例:始终需要常量表达式,而if()不';T_C_If Statement_Switch Statement - Fatal编程技术网

C 为什么案例:始终需要常量表达式,而if()不';T

C 为什么案例:始终需要常量表达式,而if()不';T,c,if-statement,switch-statement,C,If Statement,Switch Statement,可能是重复的,但找不到相同的 假设我有以下Ccode: int a; printf("Enter number :"); scanf("%d",&a); // suppose entered only an integer // ignoring return value of scanf() 我得到一个案例来检查a是零还是非零 if(a) printf("%d is non-zero",a); else printf("%d is zero"

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

假设我有以下
C
code:

int a;
printf("Enter number :");
scanf("%d",&a);  // suppose entered only an integer
                // ignoring return value of scanf()
我得到一个案例来检查
a
还是
非零

if(a)
  printf("%d is non-zero",a);
else
  printf("%d is zero",a);
使用
if-else
一切都很好,我也知道
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;
}

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

case表达式必须是常量
a
是一个变量,因此不允许使用它
0
是一个常数,所以这很好。只允许常量表达式意味着编译器更容易优化代码


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

原因是
开关
案例可以实现为跳转表(通常使用无条件分支指令)。因此,必须在编译时解决这些问题


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

除了编译时/跳转表问题之外,
if
开关
不一样,即使
case
接受一个变量,这两个代码也不会有相同的行为<当且仅当条件表达式产生非零值时,才会计算代码>如果正文;当且仅当控制表达式和标签具有相同值时,才会输入
大小写

if-then-else
switch
语句之间有很大的区别,请记住
break
s不是强制性的,如果没有任何东西阻止它,则执行会通过所有的
案例。这种行为实际上类似于跳转表,因为在
开关中执行只需跳转到某个地方,然后继续执行,直到找到一个
断点。然而,这种用法很少见,但它可能比
if-then-else
版本更有用、更容易实现

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

表格的大小写范围,lo。。hi是经过认真考虑的,但最终没有在标准中采用,因为它没有添加新的功能,只是一种有问题的编码便利性。该结构似乎承诺了超出其授权范围的内容:

  • 对于看似无辜的案例范围,例如0,可能会生成大量代码或跳转表。。65535

  • “A”的范围Z'将指定的字符代码之间的所有整数 “大写字母A”和“大写字母Z”的大写字母。在某些常用字符集中,此范围 将包括非字母字符,在其他情况下可能不包括所有字符 字母字符,特别是在非英语字符集中


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

如果你有

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语句实现为
跳转表或索引函数指针数组,而不是一系列冗长的
条件指令。这允许switch语句立即确定

无需经过比较列表即可执行分支。

这是语言创建者的设计决策。如果案例标签是常量,编译器可以通过使用跳转表来优化某些案例。如果不是,代码将与多路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语句相比,绝对没有性能优势。另一方面,如果我们要求所有条件都是常量…

跳转表?使用常量表达式,开关可能被编译成跳转表。@DanielFischer:你明白我的意思了。。是的,我想要实现。如何实现if和case,以便只需要cons