语言设计者选择在以下场景中使用花括号:
if (a)
b
while (a)
b
...
为什么在函数中不允许相同,像这样?
int add(int a, int b)
return a + b;
语言设计者选择在以下场景中使用花括号:
if (a)
b
while (a)
b
...
为什么在函数中不允许相同,像这样?
int add(int a, int b)
return a + b;
我敢肯定这会弄乱语法。例如,这个空函数定义之间没有区别......
void empty()
{
;
}
...和这个函数声明:
void empty();
我不确定他们是否“选择”了这个。相反,省略花括号 for if、while、for 等的能力是它们指定语法的方式的自然结果。语法禁止它用于函数可能是因为旧式函数声明。
没有与函数定义相关的固定关键字。使用if
/ else
/ for
/ while
/switch
有一个这样的关键字,标志着逻辑控制结构的开始。
尽管上下文允许我们人类辨别int some_name (some_expression) some_other_expressions;
函数是如何产生的 - 在编程实践中(尽管明确可行)需要大量回溯才能确保令牌流中前面的 3-4-6 个符号没有任何改变函数声明的情况到别的东西。
编程语言解析器可以通过它的解析方法进行分类,要么它获取令牌列表中的当前令牌并检查下一个令牌是否确认“这是一个 if”或“这是一个函数”,或者它需要最大的查找 -提前标记(2-3-6?)并确认“这可能是一个函数”,“现在我看到第 5 个标记这肯定是一个函数”,或者它使用带有可变前瞻方法的回溯根据需要在令牌列表中,以确保我们正在研究的构造不是别的东西。
如果我推测,我会说这是因为一个函数通常包含多个语句,而 if 或 while 语句通常只包含一个语句。此外,它被证明是有远见的,因为在 C++ 中允许省略 {} 会导致成员函数中的歧义。例如:
struct s
{
void f() const int i; //does const refer to int i or the function?
}
花括号不是“if”和“if-else”控制语句的可选组件。“if”控制语句的语法产生式允许一个非终结符跟在表达式后面。“if-else”控制语句的语法产生式允许一个非终结符跟在表达式之后,一个非终结符跟在“else”终结符之后。该非终结符的名称是 <statement>。
在控制结构(又名控制语句)的上下文中,花括号属于称为 <compound-statement>(有时称为 <block>)的语言非终结符符号。非终结符 <compound-statement> 出现在 <statement> 语法产生式的右侧,这就是为什么花括号可以与“if”和“if-else”控制语句一起使用(即,复合语句是一个语句)。
<statement> ::= <if-then-statement> |
<if-then-else-statement> |
<for-statement> |
<do-while-statement> |
...
<compound-statement>
<statement-list> ::= <statement> | <statement-list> <statement>
<if-then-statement> ::= "if" "(" <expression> ")" <statement>
<if-then-else statement> ::= "if" "(" <expression> ")" <statement> 'else' <statement>
<compound-statement> ::= "{" <statement-list> "}"
对于函数声明,<compound-statement> 非终结符是 <function-declaration> 语法产生式右侧的最后一个非终结符。
PS 所有非终结符都是语法产生。所有语法产生式都简化为一个或多个非终结符号和/或终结符号。终端符号是语言关键字。
我知道这就像一个 7 年的颠簸,但以上所有答案都不正确;尽管罗伯特库珀说这会破坏语法是正确的。
真正的问题与 C 的原始版本的外观有关:
main(argc, argv)
char *argv[];
{
puts("hello world!");
}
默认情况下,C 中的所有内容都是 int,因此可以省略很多类型注释。Modern C 完全向后兼容,因为人们不想丢弃或更新一堆现有代码。
请注意,函数参数列表之后的类型注释看起来与普通变量声明完全一样。这是故意这样做的,可能是为了简化原始语法,但这意味着尝试定义一个没有花括号的函数,就像在你的例子中那样,将是完全模棱两可的。
基本上,它不能工作,因为解析器无法区分声明语句和类型注释之间的区别。