
[英]ANSI C - direct-declarator grammar - Why does the C grammar allow syntactically legal, but sementically illegal declarations like int func()()?
[英]What is the difference between a declarator and a direct-declarator?
提示:本站为国内最大中英文翻译问答网站,提供中英文对照查看,鼠标放在中文字句上可显示英文原文。
在作者 Brian W. Kernighan 和 Dennis M. Ritchie的 C Programming Language, 2nd Edition 中,他们讨论了声明符和直接声明符。 讨论从本书第 1 页开始。 122 with dcl and direct-dcl 's 请用通俗易懂的方式解释声明符和直接声明符之间的区别好吗? 是什么让它变得直接?
另外,在第 225
其中直接声明符是标识符或带括号的标识符。 特别是,它不能通过 typedef 实现 function 类型。
在我看来declarators就是一个变量的声明或者function。在“TD”中,T部分指定了它的说明符和类型,D部分指定了identity,即变量的唯一标识名或者function。它有与语言的语法有关。
declarator是间接的,因为它们没有像direct-declarator那样被指定为直接的吗?
如今,即使是第二版 K&R 也更具历史意义而非实际意义。
尽管如此,术语“声明符”和“直接声明符”仍在当前的 C 语言规范中继续使用。 语言规范这样描述前者:
每个声明符声明一个标识符,并断言当与声明符形式相同的操作数出现在表达式中时,它指定一个 function 或 object,其中 scope、存储持续时间和类型由声明说明符指示。
(C17 6.7.6/2)
因此,“声明说明符”与“声明符”是分开的。 事实上,声明符是声明的一部分,它指定要声明的内容。
“直接声明符”是声明符的一个子集。 “直接”与指针中的“间接”形成对比。 例如,给定
int i;
int *p;
i
和*p
和p
都是句法声明符,但其中只有i
和p
是直接声明符。 并且只有i
和*p
是完整的声明符,它们不作为另一个声明符的一部分出现(如声明符p
那样)。
它变得比这更复杂——例如,将任何声明符括在括号中会产生一个直接声明符,即使就其本身而言,原始声明符不是直接声明符。
总的来说,这是一个语法上的区别,您可能不需要太担心,除非您正在为 C 语言编写解析器。 如果你这样做,那么你真的需要查看正式的语法描述。
笼统地说,声明符是一个完整的声明,而直接声明符要么是一个标识符本身,要么是一个标识符后跟[]
(使其成为一个数组)或()
(使其成为 function 或 function 指针)。
这些术语的完整定义可以在声明符的语法中找到,声明符可以在C11 标准的第 6.7.6p1 节中找到:
声明符:
- 指针选择直接声明符
直接声明符:
- 标识符
(
声明符)
- 直接声明符
[
类型限定符列表opt赋值表达式opt]
- 直接声明符
[
static
类型限定符列表选择赋值表达式]
- 直接声明符
[
类型限定符列表static
赋值表达式]
- 直接声明符
[
类型限定符列表opt*
]
- 直接声明符
(
参数类型列表)
- 直接声明符
(
标识符列表选项)
指针:
*
类型限定符列表选择*
类型限定符列表选择指针类型限定符列表:
- 类型限定符
- 类型限定符列表 类型限定符
参数类型列表:
- 参数列表
- 参数列表
,
...
参数列表:
- 参数声明
- 参数列表
,
参数声明参数声明:
- 声明说明符
- 声明说明符抽象声明符选择
该语法需要一个直接声明符标记来指定优先级。 事实上, * foo [ 3 ]
必须被解析为声明符*
后跟一个直接声明foo [ 3 ]
。 如果语法没有将声明符和直接声明符分开,则可能不清楚这是*
后跟foo [ 3 ]
组合在一起还是* foo
后跟[ 3 ]
组合在一起。
语法说声明符是:
其中指针是*
后跟可选的限定符(如const
),直接声明符是以下之一:
(
声明符)
[
类型限定符列表opt赋值表达式opt ]
[
static
类型限定符列表选择赋值表达式]
[
类型限定符列表static
赋值表达式]
[
类型限定符列表opt * ]
(
参数类型列表)
(
标识符列表选项)
因此,给定* foo [ 3 ]
,我们必须将其作为声明符, *
表示指针, foo [ 3 ]
表示直接声明符。 无法在直接声明符的开头使用*
。 因此, * foo [ 3 ]
必须声明一个包含 3 个指针的数组,而不是指向包含 3 个元素的数组的指针。
如果将declarator和direct-declarator的那些选项合并为一个语法标记,那么解析就会有歧义。 您可以将其解析为* foo [ 3 ]
因为* foo
是一个后跟[ 3 ]
的声明符,这不是我们想要的。
名字并不重要; 我们只需要额外的令牌的另一个名称。 在 C 语法中还有其他示例。 值得注意的是,表达式文法以表达式开始,然后经过一系列赋值表达式、条件表达式、逻辑或表达式等。 在您到达primary-expression之前,它们的名称与它们涉及的运算符相关联。 这与direct-declarator有一些语义相似性,表明它们都是本着“好的,我们到达了这个语法链的底部,这是主要/直接标记”的精神命名的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.