8种机械键盘轴体对比
本人程序员,要买一个写代码的键盘,请问红轴和茶轴怎么选?
switch语句的一般形式如下:1
2
3
4
5switch(表达式){
case 常量表达式:零条或多条语句
case 常量表达式:零条或多条语句
default: 零条或多条语句
}
一个遵循标准的C编译器至少允许一条switch语句中有257个case标签(ANSI C标准),这是为了允许switch满足一个8bit字符的所有情况(256个可能的值加上EOF)。
每个case结构由3部分组成:关键字case;紧随其后的常量值或常量表达式;再紧接一个冒号。看一个例子:1
2
3
4
5
6
7
8
9
10
11int main(){
int i=0,j=0;
const int a = 2;
switch(i){
case 1: j=1;
case a: j=2;
case 3: j=3;
default: j=4;
}
return 0;
}
编译出错:
case a: j=2;
error: case label does not reduce to an integer constant
从这里不仅可以看出const修饰的变量并不代表就是常量,而且case后面必须为常量值或常量表达式。
a.当表达式的值与case中的常量匹配时,该case后面的语句就会执行。
b.default(如果有的话)可以出现在case列表的任意位置,但习惯上总是把default放在最后,它在其他的case均无法匹配时被选中执行。
c.如果没有default,而且所有的case均不匹配,那整条switch语句便什么都不做。
switch存在的问题:
其一:可以在switch的左花括号之后声明一些变量,但变量不会被初始化。
例如,可以在switch的左花括号之后声明一些变量,从而进行一些局部存储的分配。在最初的编译器里,这是一个技巧——绝大多数用于处理任何复合语句的代码都可以被复用,可以用于处理switch语句中由花括号包住的那部分代码。所以在这个位置上声明一些变量会被编译器很自然的接受,尽管在switch语句中为这些变量加上初始值是没有什么用处的,因为它绝不会被执行——语句从匹配表达式的case开始执行。示例如下:1
2
3
4
5
6
7
8
9
10
11
12
13int main(){
int i=0,j=0;
switch(i){
int a = 2;
case 1: j=1;
case 2: j=2;
case 3: j=3;
default: j=4;
printf("%dn",a);
}
printf("%dn",j);
return 0;
}
编译时警告:
printf(“%dn”,a);
warning: ‘a’ is used uninitialized in this function [-Wuninitialized]
运行结果显示:
0
4
在C语言中,当建立一个块时,一般总是这样开始的:
{
语句
}
你总是可以在两者之间增加一些声明,如:
{
声明
语句
}
当分配动态内存代价较高时,你可能会采用这种局部存储的方法,但有可能的话要尽量避免,编译器可以自由的忽略它,它可以通过函数调用来分配所有局部块需要的内存空间。
另一种用法是声明一些完全局部于当前块的变量:1
2
3
4
5
6
7
8
9
10int main(){
int a = 2,b = 1;
if(a > b){
int temp = a;
a = b;
b = temp;
}
printf("a = %d, b = %dn",a,b);
return 0;
}
运行输出:
a = 1, b = 2
若增加代码:1
2
3
4
5
6
7
8
9
10
11int main(){
int a = 2,b = 1;
if(a > b){
int temp = a;
a = b;
b = temp;
}
printf("temp = %dn",temp);
printf("a = %d, b = %dn",a,b);
return 0;
}
编译出错:
printf(“temp = %dn”,temp);
error: ‘temp’ undeclared (first use in this function)
可见,变量temp完全局部于if语句的代码块。
C++在这方面又进了一步,允许语句和声明以任意的顺序出现,甚至允许变量的声明出现在for表达式的内部:1for(int i = 0; i<100; i++){ ... }
其二:switch内部任何语句都可以加上标签。
switch内部任何语句都可以加上标签,并在执行时跳转到那里,这就有可能破坏进程流的结构化。示例:1
2
3
4
5
6
7
8
9
10int main(){
int i = 2;
switch(i){
case 5+3: do_again:
case 2: printf("loopn");goto do_again;
default: i++;
case 3: ;
}
return 0;
}
上述代码执行时,进程循环输出“loop”。
同时,平时在其他地方,为了避免破坏进程流的结构化,应当尽量不要使用goto语句。
其三:对case可能出现的值太过于放纵了。
所有的case都是可选的,任何形式的语句——包括带标签的语句都是允许的。这就意味着有些错误很难检测出来。代码示例:1
2
3
4
5
6
7
8
9
10
11int main(){
int i = 2;
switch(i){
case 5+3: ;
case 2: printf("loopn");
defau1t: i++;
case 3: ;
}
printf("%dn",i);
return 0;
}
上述代码将default的字母l变为数字1,编译警告:
defau1t: i++;
warning: label ‘defau1t’ defined but not used [-Wunused-label]
此时default由语句变为一个标签,进程仍然能够执行,执行输出结果:
loop
3
其四:最大的缺点——fall through
switch不会在每个case标签后面的语句执行完毕后自动终止。一旦执行某个case语句,进程将会依次执行后面所有的case,除非遇到break语句。代码示例:1
2
3
4
5
6
7
8
9
10int main(){
switch(2){
case 1: printf("case 1n");
case 2: printf("case 2n");
case 3: printf("case 3n");
case 4: printf("case 4n");
default: printf("defaultn");
}
return 0;
}
输出结果为:1
2
3
4case 2
case 3
case 4
default
这称之为“fall through”,意思是:如果case语句后面不加break,就依次执行下去,以满足某些特殊情况的要求。但实际上,这是一个非常不好的特性,因为几乎所有的case都需要以break结尾。在大多数情况下,你不希望因这个缺省的行为而不得不加上一条额外的break语句来改变它。
其五:break到底中断了什么。
先看一段有bug的代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21int main(){
int i = 2,a = 0,b = 1;
switch(i){
case 1:
printf("case 1n");
break;
case 2:
if(a == 0){
printf("step 1n");
if(b ==1)
break;
printf("step 2n");
}//代码意图是跳到这里
printf("step 3n");
b++;
break;
default: printf("defaultn");
}//事实是跳到这里
printf("b = %dn",b);
return 0;
}
进程输出:
step 1
b = 1
所以,从上面可以体会到,break语句跳出的是最近的那层循环语句或switch语句。if中的break语句使得代码直接跳出switch语句。在C语言中,不要低估”break“语句对控制结构的影响,慎重使用。
故综上,switch语句的一般形式为:1
2
3
4
5
6
7
8
9
10switch(表达式){
case 常量表达式:
零条或多条语句;
break;
case 常量表达式:
零条或多条语句;
break;
default:
零条或多条语句;
}