Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/63.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
在switch情况下有效但毫无价值的语法?_C_Switch Statement_Language Lawyer - Fatal编程技术网

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