当前位置:  开发笔记 > 编程语言 > 正文

在switch-case中有效但无价值的语法?

如何解决《在switch-case中有效但无价值的语法?》经验,为你挑选了8个好方法。

通过一个小错字,我意外地发现了这个结构:

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的顶部switch是有效的,但也完全无法访问.

我得到了一个干净的编译,甚至没有关于无法访问的代码的警告,但这似乎毫无意义.

编译器是否应将此标记为无法访问的代码?
这有什么用途吗?



1> AlexD..:

也许不是最有用的,但并非完全无价值.您可以使用它来声明switch范围内可用的局部变量.

switch (foo)
{
    int i;
case 0:
    i = 0;
    //....
case 1:
    i = 1;
    //....
}

standard(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.

PS BTW,示例是无效的C++代码.在那种情况下(N4140 6.7/3强调我的):

除非变量具有标量类型,具有普通默认构造函数的类类型和普通析构函数,否则从具有自动存储持续时间的变量不在范围内的点跳到90的程序是不正确的.这些类型之一的cv限定版本,或者前面类型之一的数组,并且在没有初始值设定项的情况下声明(8.5).


90)从switch声明条件到案件标签的转移被认为是这方面的一个跳跃.

因此,更换int i = 4;int i;使它成为一个有效的C++.


@yano我们总是跳过`i = 4;`初始化,所以它永远不会发生.
哈,当然!...问题的全部要点...... geez.删除这种愚蠢的欲望很强烈
请注意,如果变量是"static",它将被初始化为零,因此也可以安全使用它.
"......但是从未初始化......"看起来`i`被初始化为4,我错过了什么?

2> 小智..:

这有什么用途吗?

是.如果不是声明,而是在第一个标签之前放置一个声明,这可能是完全合理的:

switch (a) {
  int i;
case 0:
  i = f(); g(); h(i);
  break;
case 1:
  i = g(); f(); h(i);
  break;
}

声明和语句的规则一般是为块共享的,所以它允许的那个规则也允许那里的语句.


值得一提的是,如果第一个语句是循环结构,则case标签可能出现在循环体中:

switch (i) {
  for (;;) {
    f();
  case 1:
    g();
  case 2:
    if (h()) break;
  }
}

如果有更可读的编写方式,请不要编写这样的代码,但它完全有效,并且f()可以访问调用.


我不确定我是否应该为这个有趣的例子投票,或者为了在真实的程序中写这个完全疯狂而投票.恭喜潜入深渊并重新回到原点.

3> Yakk - Adam ..:

有一种名为Duff's Device的着名用途.

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);
}

这里我们将指向的缓冲区复制到指向from的缓冲区to.我们复制count数据实例.

do{}while()语句在第一个case标签之前开始,case标签嵌入在标签中do{}while().

这减少了条件分支的数量 do{}while()循环大约减少了4倍(在此示例中,常量可以调整为您想要的任何值).

现在,优化器有时可以为您执行此操作(特别是如果它们正在优化流/矢量化指令),但如果没有配置文件引导优化,它们无法知道您是否期望循环变大.

通常,变量声明可以在那里出现并在每种情况下使用,但在切换结束后超出范围.(注意任何初始化都会被跳过)

此外,非特定于交换机的控制流可以让您进入交换机块的该部分,如上所示,或者使用goto.


当然,如果不允许在第一种情况之上的语句,这仍然是可能的,因为`do {`和`case 0:`的顺序无关紧要,两者都用于在第一个`*to =*上放置一个跳转目标从++;`.

4> 小智..:

假设您在Linux上使用gcc,如果您使用的是4.4或更早版本,它会给您一个警告.

-wunreachable-code选项在gcc 4.4之后被删除.



5> Sanchke Dell..:

不仅用于变量声明,还用于高级跳跃.当且仅当您不喜欢意大利面条代码时,您可以很好地利用它.

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是最快的控制流条款之一.所以程序员必须非常灵活,有时会涉及这样的情况.



6> cmaster..:

应该注意的是,switch声明中的代码几乎没有结构限制,或者case *:标签放在此代码中的位置*.这使得编程技巧像duff的设备成为可能,其中一个可能的实现如下所示:

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: ;
    }
}

你看,标签switch(n%8) {case 7:标签之间的代码肯定是可以达到的......


*作为supercat,谢天谢地在评论中指出:自C99以来,既不是goto标签也不是标签(无论是否为case *:标签)都可能出现在包含VLA声明的声明范围内.因此,对标签的放置没有结构限制是不正确的case *:.然而,duff的设备早于C99标准,并且它无论如何都不依赖于VLA.尽管如此,由于这个原因,我觉得不得不在我的第一句话中加入"虚拟".



7> Sourav Ghosh..:

您得到了与生成警告所需gcc选项 相关的答案-Wswitch-unreachable,这个答案是详细说明可用性/值得部分.

直接引用C11,第6.8.4.2章,(强调我的)

switch (expr)
{
int i = 4;
f(i);
case 0:
i = 17;
/* falls through into default code */
default:
printf("%d\n", i);
}

标识符i存在的对象具有自动存储持续时间(在块内)但从未初始化,因此如果控制表达式具有非零值,则对printf 函数的调用将访问不确定的值.同样,无法访问函数调用f.

这是非常不言自明的.您可以使用它来定义本地范围的变量,该变量仅在switch语句范围内可用.



8> celtschk..:

使用它可以实现"循环和半",尽管它可能不是最好的方法:

char password[100];
switch(0) do
{
  printf("Invalid password, try again.\n");
default:
  read_password(password, sizeof(password));
} while (!is_valid_password(password));

推荐阅读
小白也坚强_177
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有