为啥“defau4t”在 switch 语句中是合法的? [复制]

Posted

技术标签:

【中文标题】为啥“defau4t”在 switch 语句中是合法的? [复制]【英文标题】:Why is "defau4t" legal in a switch statement? [duplicate]为什么“defau4t”在 switch 语句中是合法的? [复制] 【发布时间】:2014-09-16 12:12:04 【问题描述】:

我在其他网站上提出了这个程序并想尝试一下,程序如下:

#include <stdio.h>
int main()

    int a=10;
    switch(a)
    
         case '1': printf("one");
                   break;
         case '2': printf("two");
                   break;
         defau4t:  printf("none");
    
    return 0;

令人惊讶的是,它编译时没有错误或警告。这怎么可能?关键字“默认”没有错误吗? 谁能解释这种行为?

【问题讨论】:

编译器将其解释为goto 标签。 gcc 在警告中解释:14:10: warning: label 'defau4t' defined but not used @darknight:您是否至少在没有-Wall -Wextra 的情况下使用GCC? ;-) @darknight:那么,你在一个问题中学到了两件事。 ;-) 您应该始终将 gcc 称为 gcc -std=c99 -pedantic-errors -Wall -Wextra(其中 c99 可以替换为 c11 或 c90)。将其称为gcc test.c 不仅会错过许多危险的练习,还会期望您通过一个用某种幻想的非标准 GNU 语言而不是 ISO 标准 C 语言编写的程序。 【参考方案1】:

令牌根本不被视为关键字。这是一个名为“defau4t”的goto 跳转标记,指向其他死代码(在case '2':break; 之后)...

试试这个笑(和一个无限循环):

switch(a)

     case '1': printf("one");
               break;
     case '2': printf("two");
               break;
     defau4t: printf("none");
     default: goto defau4t;

【讨论】:

好的,那么当我实际使用默认值时会发生什么? 在你的情况下,这个开关将被省略。 好的编译器会对从未使用过的 goto-labels 发出警告......至少如果你问得好:-Wall -Wextra -pedantic @Mr.32:优化是一个棘手的主题,必然会随着编译器版本和使用的编译器标志而改变。编译器可以优化 OP 源代码中的死代码,警告它,或者什么都不做。 @JaeHyukLee: 否。gotocase / default 标签不可互换(AFAIK),它们只是共享一个通用语法(尾随冒号)。在我的代码中,case '1':case '2':default:switch 构造的一部分。 defau4t: 是一个跳转标签,它恰好是 in switch 构造。 goto case '1': 的任何值都不能超过 a 的任何值可以跳转到 defau4t:【参考方案2】:

switch 语句的一个缺陷是您可以使用goto 疯狂地跳入和跳出它们。在switch 内的任何一点(或在它之外),您可以放置​​一个标签,您可以使用goto 跳转到该标签。当然,这是非常糟糕的做法,因为它会导致意大利面条式代码。

所以defau4t: 只是一个标签,标签几乎可以放在函数体内的任何位置。

【讨论】:

@DevSolar goto 的两个好用处:跳出嵌套循环(当然可以使用“shouldExit”布尔值,但它丑陋且效率较低) - 以及函数内的错误处理。 @DevSolar 问题在于casedefault 看起来像标签,行为也像标签。此外,如果您忘记了break,该开关还具有一些内置的“意大利面条功能”,例如危险的跌落机制,如您自己的示例所示。当您将几个意大利面条功能混合在一起时,您会得到糟糕的代码。 @JamesMcLaughlin 这些不是“好的”用途,而是可以容忍的用途。 50 年前的 goto 辩论的共识是,程序员确实认识到使用 goto 是有正当理由的,但无论如何我们都不应该使用它,因为它是 100% 多余的特性。整个 goto 辩论本身就足以避免它...... :) @Lundin:嗯,有人在上面画的大 666 是避免它的好理由,是的。但即使是 Djikstra 也从未主张永久禁止,只是为了给结构化编程一个机会,这是最简洁(且足够高效)的替代方案。好的代码使用goto,它是最好的工具,没有别的地方。 每个使用for的代码都可以重构为使用while,每个使用switch的代码都可以重构为使用一系列ifelse。反对每次使用goto 是一种宗教废话。您可以更好地把精力花在与明显糟糕的代码作斗争或编写好的代码上。【参考方案3】:

除了那个默认的错字。

我认为你也需要更新

     case '1': printf("one");
               break;
     case '2': printf("two");
               break;

     case 1: printf("one");
               break;
     case 2: printf("two");
               break;

【讨论】:

这取决于'1''2' 是否是拼写错误,或者他是否真的想要检查字符“1”的实现定义的编码值和“2”,其中一个实际上可能等同于他选择的平台上的(int)10。 ;-)(+1 当然,你是绝对正确的。) 不.. 这不是问题,无论哪种方式,我的意思是转到默认情况 这不是问题的真正答案,只是对代码的评论。

以上是关于为啥“defau4t”在 switch 语句中是合法的? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

为啥这个 switch 语句在运行时会结束 while 循环?

为啥这个简单的switch语句总是运行默认

为啥 switch 语句没有大括号?

为啥“switch”语句在设置 UICollectionView 的标题时不起作用?

为啥我不能在 switch 语句中使用元组常量作为案例

为啥在 if 语句中初始化字符串似乎与在 switch 语句中不同? [复制]