在switch情况下有效但毫无价值的语法?
通过一点输入错误,我意外地发现了这个结构:在switch情况下有效但毫无价值的语法?,c,switch-statement,language-lawyer,C,Switch Statement,Language Lawyer,通过一点输入错误,我意外地发现了这个结构: int main(void) { char foo = 'c'; switch(foo) { printf("Cant Touch This\n"); // This line is Unreachable case 'a': printf("A\n"); break; case 'b': printf("B\n"); break; case 'c': pr
int main(void) {
char foo = 'c';
switch(foo)
{
printf("Cant Touch This\n"); // This line is Unreachable
case 'a': printf("A\n"); break;
case 'b': printf("B\n"); break;
case 'c': printf("C\n"); break;
case 'd': printf("D\n"); break;
}
return 0;
}
似乎开关
语句顶部的printf
是有效的,但也是完全不可访问的
我得到了一个干净的编译,甚至没有关于无法访问代码的警告,但这似乎毫无意义
编译器是否应该将此标记为无法访问的代码?这有什么用吗?假设您在Linux上使用gcc,如果您使用的是4.4或更早版本,它会给您一个警告
-Wunreachable代码选项以后。也许不是最有用的,但也不是完全没有价值的。您可以使用它来声明
switch
范围内可用的局部变量
switch (foo)
{
int i;
case 0:
i = 0;
//....
case 1:
i = 1;
//....
}
标准(N1579 6.8.4.2/7
)有以下示例:
人工程序片段中的示例
switch (expr)
{
int i = 4;
f(i);
case 0:
i = 17;
/* falls through into default code */
default:
printf("%d\n", i);
}
标识符为i
的对象以自动存储持续时间(在块内)存在,但从不存在
初始化,因此如果控制表达式具有非零值,则调用printf
函数将
访问一个不确定的值。同样,无法调用函数f
<强> P.S. BTW,该示例不是有效的C++代码。在这种情况下(
N4140 6.7/3
,强调我):
一种程序,从一个具有自动存储持续时间的变量不在范围内的点跳90到另一个点
除非变量具有标量类型、类类型和一个微不足道的默认值,否则它在作用域中的点是格式错误的
构造函数和普通析构函数、这些类型之一的cv限定版本或其中一个类型的数组
前面的类型,声明时没有初始值设定项(8.5)
90)在这方面,从
开关
语句的状态转移到案例标签被视为跳转
因此,替换
inti=4代码>带有inti代码>使其成为有效的C++。< p>您得到了与<代码> -Wwitter不可及的< /代码>有关的答案以生成警告,此答案是在可用性/有价值部分阐述。
直接引用C11
,第§6.8.4.2章(重点)
标识符为i
的对象存在并自动存储
持续时间(在块内),但从未初始化,因此如果
控制表达式有一个非零值,即调用printf
函数将访问一个不确定的值。同样,呼吁
无法访问功能f
这是不言自明的。您可以使用它来定义一个局部范围的变量,该变量仅在开关
语句范围内可用
这有什么用吗
对。如果您在第一个标签前放置声明而不是语句,则这会非常有意义:
switch (a) {
int i;
case 0:
i = f(); g(); h(i);
break;
case 1:
i = g(); f(); h(i);
break;
}
声明和语句的规则通常是为块共享的,因此这与允许声明和语句的规则相同
同样值得一提的是,如果第一条语句是循环构造,则循环体中可能会出现大小写标签:
switch (i) {
for (;;) {
f();
case 1:
g();
case 2:
if (h()) break;
}
}
如果有一种更可读的编写方法,请不要这样编写代码,但它是完全有效的,并且可以访问f()
调用。不仅用于变量声明,也用于高级跳转。如果且仅当您不喜欢使用意大利面代码时,您就可以很好地利用它
int main()
{
int i = 1;
switch(i)
{
nocase:
printf("no case\n");
case 0: printf("0\n"); break;
case 1: printf("1\n"); goto nocase;
}
return 0;
}
印刷品
1
no case
0 /* Notice how "0" prints even though i = 1 */
应该注意的是,开关盒是最快的控制流条款之一。因此,它对程序员来说必须非常灵活,有时会涉及类似的情况。应该注意的是,在switch
语句中的代码,或者在case*:
标签放置在此代码*中的位置,实际上没有结构限制。这使得编程技巧成为可能,其中一种可能的实现如下所示:
int n = ...;
int iterations = n/8;
switch(n%8) {
while(iterations--) {
sum += *ptr++;
case 7: sum += *ptr++;
case 6: sum += *ptr++;
case 5: sum += *ptr++;
case 4: sum += *ptr++;
case 3: sum += *ptr++;
case 2: sum += *ptr++;
case 1: sum += *ptr++;
case 0: ;
}
}
你看,开关(n%8){
和案例7:
标签之间的代码肯定是可以到达的
*As:自C99以来,既不是转到
也不是标签(无论是案例*:
标签还是非标签)可能出现在包含VLA声明的声明范围内。因此,说对大小写*:
标签的放置没有结构限制是不正确的。但是,达夫的设备早于C99标准,并且它无论如何都不依赖于VLA。尽管如此,我还是觉得必须插入一个“虚拟的”因此,在我的第一句话中。可以使用它实现“半循环”,尽管这可能不是最好的方法:
char password[100];
switch(0) do
{
printf("Invalid password, try again.\n");
default:
read_password(password, sizeof(password));
} while (!is_valid_password(password));
这个词有一个著名的用法叫做
这里我们将指向的缓冲区从
复制到指向
的缓冲区。我们复制计数
数据实例
do{}while()
这将减少do{}while()
循环末尾遇到的条件分支的数量,大约减少了4倍(在本例中,可以将常量调整为所需的任何值)
现在,优化器有时可以为您这样做(特别是在优化流式/矢量化指令时),但如果没有概要文件引导的优化,他们无法知道您是否期望循环很大
一般来说,变量声明可以出现在那里,并且在任何情况下都可以使用,但在切换结束后都会超出范围。(注意,任何初始化都将被跳过)
此外,非交换机特定的控制流可以让您进入交换机块的该部分,如上图所示,或者使用goto
GCC有一个特殊的标志。
char password[100];
switch(0) do
{
printf("Invalid password, try again.\n");
default:
read_password(password, sizeof(password));
} while (!is_valid_password(password));
int n = (count+3)/4;
switch (count % 4) {
do {
case 0: *to = *from++;
case 3: *to = *from++;
case 2: *to = *from++;
case 1: *to = *from++;
} while (--n > 0);
}