c - ANSI C - 直接声明符语法 - 为什么 C 语法允许语法上合法但语义上非法的声明,如 int func()()?
问题描述
ANSI C 语法规定:
declarator:
pointer_opt direct-declarator
direct-declarator:
identifier
( declarator )
direct-declarator [ constant-expression_opt ]
direct-declarator ( parameter-type-list )
direct-declarator ( identifier-list_opt )
根据这个语法,可以推导出
func()()
作为声明者,并且
int func()()
作为声明,这在语义上是非法的。为什么 C 语法允许这种语法上合法但语义上非法的声明?
解决方案
这类问题通常无法确定地回答,因为您正在询问有关1989 年C 委员会的集体思想和审议的信息。他们从未像负责 Python 的人那样完全公开地进行语言开发工作,而 30 年前他们这样做的更少。如果你亲自对他们进行调查,他们可能不会记得。
我们可以查看C Rationale 文档(我链接到与 C1999 对应的版本,但据我所知,它自 1989 年以来并没有太大变化)寻找线索,但快速浏览一下,我看不到与您的问题相关的任何内容。
这让我根据编程语言设计的一般原则进行猜测。有一个与您的问题相关的一般原则:特别是对于较旧的语言,设计人员试图使形式语法尽可能地与上下文无关。这使得编写高效的解析器变得更加容易。诸如“你不能有一个返回函数的函数”之类的规则需要上下文,因此它们被排除在语法之外。将它们作为应用于解析树的事后约束来处理很简单,这就是设计人员所做的。
C 语法有一大堆地方似乎已经使用了这个原则,而不仅仅是你要问的那个。例如,存在用于标记化的“最大咀嚼”规则是因为它意味着标记器不需要知道完整的解析器上下文,即使它会导致不方便的结果,例如a-----b
被解释为a -- -- - b
而不是a -- - -- b
,即使解析器将拒绝前者,接受后者。
这种编程语言的设计原则常常令初学者感到惊讶,因为它与人类理解自然语言的方式大不相同。我们会不遗余力地从最荒谬的句子中“修复”某种上下文适当的含义,我们实际上在对话中依赖于此。考虑越差越好的元原则可能会有所帮助(过于简单化,因为您可以快速完成前 90% 的工作并将其放在那里,然后对剩余的 90% 进行迭代)。
推荐阅读
- qt - 有没有办法用QML TextEdit 的 selectedText 属性中的替代文本替换标签
- r - 选择表中的行,然后提取键并在另一个表中搜索并在 R 中显示行闪亮
- typescript - TypeScript 编译器 API 获取映射属性的类型
- python - 在发布 API 之前休眠 X 秒 - Python
- .net-core - 具有 IPEndPoint 的 TcpClient 失败,但具有相同 IPEndPoint.Address 的 TcpClient 没有?
- javascript - 是否可以在 laravel 中通过 AJAX 更改 URL?
- reactjs - 使用 Promises 的 Jest 模拟静态方法
- python - Python global variables for DataFrames
- javascript - django ajax keep appending the same result
- firebase - Google Storage - only auth users and no delete / rewrite