【问题标题】:spaces not needed in case labels?案例标签中不需要空格?
【发布时间】:2015-02-26 17:23:45
【问题描述】:

这可能是一个愚蠢的问题,但是否有人已经知道case 关键字与其在switch 语句中的常量表达式之间是否存在强制空格?

标准似乎没有说明...

考虑以下代码:

switch(int_expression)
{
    case1:     /*anything*/  // no space before 1
    caseZERO:  /*anything*/  // no space before ZERO
                             // ZERO being defined as 0
                             // by the pre-processor
}

我的两个参考编译器都接受此代码,并且一旦运行它就可以很好地工作。 预处理器如何识别必须替换零?

另请注意,如果控制表达式是 char 类型而不是 int 类型,则以下内容也会被编译,但这次不再有效

switch(char_expression)
{
    case'a':   /* anything */  // NO SPACES embedded
    caseZERO:  /* anything */  // NO SPACES again
                               // ZERO being defined as '0'
                               // by the pre-processor
}

这个编译但是即使char_expression 的值是'0' caseZERO 中没有任何语句被执行。

谁能解释一下?

【问题讨论】:

  • 标识符后跟冒号也是标签(用于 goto)。我敢打赌这就是caseZERO 在这种情况下的含义。我还希望控制它的规则在定义什么是令牌的部分中,并且语法需要一个令牌case,但得到一个令牌caseZERO。出于同样的原因,ZERO 也没有展开。但我不是标准方面的专家,所以我会让其他人回答。
  • 有趣。我想知道标准对没有案例标签的开关有什么看法
  • @sp2danny:它可能允许它们,但会跳过 switch 语句/块——类似于 if (0)
  • 为了让编译器识别case,需要用空格将case 与其值分开。正如其他人所说,没有空格,标识符被视为标签(例如,对于 goto 语句)。
  • @sp2danny:这完全有效,语法是switch ( expression ) statement,甚至switch(0); 也是一个有效的空操作。

标签: c++ c switch-statement


【解决方案1】:

这些是与goto 一起使用的通用标签,实际上不会按照您的意图匹配表达式。语法有效,但语义不同。

您没有指定这是 C 编译器还是 C++ 编译器,因此这里也是 C 中 goto 的文档。

此外,如果您查看附录 A.2.3 (6.8.1) 中 ISO C 标准提供的实际语法,则定义如下 labeled-statement

(6.8.1) 标签声明:

标识符 : 声明

case 常量表达式 : 语句

默认 声明

请特别注意,case 是一个单独的标记,在语法上下文中必须后跟至少一个标记分隔字符。 case1 示例中的数字不算作标记分隔字符,因此您的示例属于语法的第一个分支,它是 identifier not a case 语句,因此不能用作switch 语句的目标。

要回答您关于在预处理器宏中定义ZERO 的其他问题,您认为替换没有发生。同样,预处理器对标记进行操作,因此caseZERO 是一个与ZERO 宏不匹配的单个标记,因此根本不会被替换。同样,这只是使用 identifier 分支定义一个 labeled-statement,其中标识符是整个令牌 caseZERO,而不是您认为的 case0case'0' .预处理器确实可以使用## 运算符进行“令牌粘贴”,但这需要您使用case ## ZERO。但是,这仍然不会产生您可能想要的行为。

【讨论】:

    【解决方案2】:

    case 表达式的类型不相关。重要的是句法形式。

    switch (expr) {
        caseZERO: /*...*/;
        case0:    /*...*/;
        case'a':  /*...*/;
    }
    

    caseZEROcase0 都是有效标识符。在这种情况下,它们是标签,而不是case 标签。如果你有一个声明

     goto caseZERO;
    

     goto case0;
    

    在同一个函数中,它会分支到相应的标签语句。

    (这是 C 语言中的许多情况之一,其中拼写错误导致代码在语法上仍然有效,但含义却大不相同。)

    另一方面,

    case'a'两个 标记,因为'a' 是一个字符常量。 (但为了人类读者的利益,它仍然应该写成case 'a':。)

    将源代码拆分为标记的规则要求在标识符、关键字或数字文字与另一个标识符、关键字或数字文字之间有空格,否则会产生歧义。它们确实在其他上下文中需要空格。这就是为什么,例如,你可以这样写:

     x=y+func(42);
    

    而不是

     x = y + func ( 42 ) ;
    

    添加一些空格将使代码对人类读者更易读:

    x = y + func(42);
    

    但编译器不在乎。

    (另一种空格很重要的情况是在类函数宏的定义中。( 必须紧跟在宏名称之后;否则它被视为扩展的第一个标记,而不是引入参数列表。)

    【讨论】:

    • 感谢大家的宝贵回答:现在一切都清楚了……这个问题真的很愚蠢。
    猜你喜欢
    • 2016-09-05
    • 1970-01-01
    • 2014-10-07
    • 1970-01-01
    • 1970-01-01
    • 2013-08-09
    • 2020-05-06
    • 1970-01-01
    • 2019-03-08
    相关资源
    最近更新 更多