可能这是一个愚蠢的问题,但有没有人知道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
}
我的参考编译器都接受这个代码,一旦运行它就可以正常工作。 预处理器如何识别ZERO必须被替换?
另请注意,如果控件表达式是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
中没有声明被执行。
任何人都能解释一下吗?
答案 0 :(得分:8)
这些是与goto
一起使用的常规标签,并不会按照您的意图实际匹配表达式。语法有效,但语义不同。
您没有指定这是C编译器还是C ++编译器,所以这里也是C语言中goto
的文档。
另外,如果您查看附录A.2.3(6.8.1)中ISO C标准提供的实际语法,则定义标记语句,如下所示:
(6.8.1)标签声明:
标识符 : 声明
案例 常量表达式 : 声明
默认 : 声明
特别注意case
是一个单一的标记,在语法的上下文中必须至少有一个标记分隔字符。 case1
示例中的数字不算作标记分隔字符,因此您的示例属于语法的第一个分支,即标识符 不 case
语句,因此不能用作switch
语句的目标。
要回答有关在预处理器宏中定义ZERO
的其他问题,您认为替换不会发生。同样,预处理器对令牌进行操作,因此caseZERO
是与ZERO
宏不匹配的单个令牌,因此根本不会被替换。同样,这只是使用标识符分支定义标记语句,其中标识符是整个标记caseZERO
而不是case0
或{{ 1}}如你所愿。预处理器确实有使用case'0'
运算符进行“令牌粘贴”的方法,但这需要您使用##
。但是,这仍然没有您可能想要的行为。
答案 1 :(得分:3)
案例表达式的类型无关紧要。它是重要的句法形式。
switch (expr) {
caseZERO: /*...*/;
case0: /*...*/;
case'a': /*...*/;
}
caseZERO
和case0
都是有效的标识符。在此上下文中,它们是标签,但不是 case
标签。如果您有声明
goto caseZERO;
或
goto case0;
在同一个函数中,它将分支到相应的带标签语句。
(这是C语言中的众多案例之一,其中拼写错误导致代码在语法上仍然有效,但意义却截然不同。)
另一方面, case'a'
是两个标记,因为'a'
是字符常量。 (但为了人类读者的利益,它仍应写成case 'a':
。)
将源代码拆分为标记的规则要求标识符,关键字或数字文字与另一个标识符,关键字或数字文字之间有空格,否则它将是不明确的。他们不在其他环境中需要空格。这就是为什么,例如,你可以写:
x=y+func(42);
而不是
x = y + func ( 42 ) ;
添加一些空白区域将使代码对人类读者更易读:
x = y + func(42);
但是编译器并不关心。
(空格很重要的另一种情况是函数式宏的定义。(
必须紧跟宏名称;否则它被视为扩展的第一个标记,而不是介绍参数列表。)