通过 K&R 的 C 书籍第 2 版理解 C 声明
Posted
技术标签:
【中文标题】通过 K&R 的 C 书籍第 2 版理解 C 声明【英文标题】:Understanding C declarations through K&R's C book, 2nd ed 【发布时间】:2015-11-11 21:27:38 【问题描述】:我刚读完 K&R 的“C 编程语言”第 2 版的语言参考(附录 A),以便找到一份新工作。
请注意,我已经通过此处关于 SO 的所有指南了解了如何阅读 C 声明(非常感谢 ;))。解释一直是对 C 中表达式和运算符优先级的引用。 我可以从参考手册(即该书的附录 A,§A7)中推断出相同的优先级表,没问题。
但是,§A7 处理表达式运算符的优先级,如本节开头所述 - 方括号 postfix-expression [ expression ]
在本文中被视为下标运算符,星号 *
被视为间接运算符和括号 ( argument-expression-list)
或 ()
与函数调用有关,请参阅 §A7.3。那么当主题是 C 声明时,为什么这么多人引用此优先级表,甚至得到一对对 SO 的支持?它声称定义的唯一优先级是某些表达式运算符的优先级。
如何解析声明在 §A8 中进行了说明,尤其是 §A8.6 涉及更复杂声明的基础知识。 但在整个附录 A 中,并没有说明要解析括号、方括号、星号、类型名称等的确切优先级。 在第 216 页上它说,括号可能会改变复杂声明符的绑定,但现在 如何(虽然我有预感,请参见下面的示例)。
让我在“伪代码”中举一个例子,我 am 不知所措,使用 §A8.8(T 代表类型说明符,D 代表声明符) :
读取 C 声明:
Original declaration:
char (*(*f())[])()
/* Have to use A8.6.3, because of how the decl. looks: */
Now let T=char , D=(*(*f())[])()
D=D1(), where D1=(*(*f())[])
The type of f, according to A8.6.3 is then
:L1 /* label 1 */
f is "type-modifiers of f in D1" function returning char /* note, in the book it says 'type-modifiers of f in T D1, but this wouldn't make any sense! */
Now look at T D1 = char (*(*f())[])
:ALT_A
The type of f in D1 = (*(*f())[]) is the same as that of f in
D2=*(*f())[]
/* At least, this is how parentheses are supposed to be understood, according to the beginning of A8.6,
where it says:
In a declaration T D where D has the form
( D1 )
then the type of the identifier in the declaration D1 is the same as that of D. */
/* note about that quote: the identifier in D has no type, did the authors mean to imply 'incomplete' types?
So, using incomplete types:*/
Looking at D2 = T1 D3[] ----> have to use A8.6.2, where T1 = * , D3 = (*f()),
so the type of f in T1 D3 is
f is "type-modifiers of f in D3" array of pointers ()
look at f in D3 = (*f()), or equivalently, f in D4 = *f(). Have to use A8.6.3. --->
f is a function returning a pointer to ()
going up a level: f is "type-modifiers of f in D3" array of pointers ()
translates to: f is a function returning a pointer to an array of pointers ()
going up another level: f is "type-modifiers of f in D1" function returning char
translates to: f is a function returning a pointer to an array of pointers to functions returning a char
这是结果,cdecl 也显示。 请注意,我没有使用任何优先级表,只是参考手册和与声明直接相关的部分。
那么这么多人如何以及为什么提到运算符优先级? 在我看来,当人们询问 C 声明时,对运算符优先级的每一次引用都是一个错误的答案,给出了一个“解析算法”,结果神奇地得出了正确的结果。
其次,为什么 K&R 似乎对这么多东西如此不精确(请参阅伪代码中的 /* */-remarks)?我本来期望更精确,我的意思是他们显然知道所有细节并且必须能够精确地思考。
抱歉,格式混乱,顺便说一句。我花了一天的大部分时间试图写下我如何手动解析这个,同时理解 K&R 对这个和那个公式可能意味着什么......
源列表,其中声明和运算符优先级被称为连接:
http://users.ece.utexas.edu/~ryerraballi/CPrimer/CDeclPrimer.html (“所有人都必须了解任何复杂的 C 声明,就是要知道这些声明是基于 C 运算符优先级图表的,与您在 C 中用于评估表达式的相同:”)
http://binglongx.com/2009/01/25/how-to-read-a-cc-declaration/
How are (complex) declarations parsed in terms of precedence and associativity? (“事实上,C 的设计者足够明智地使声明使用与表达式相同的“优先规则”。这是“声明遵循用法”规则。例如,在表达式中”,请参阅 Brian 的第一个答案。)
Operator precedence in C Definitions
专家 C 编程:深度 C 的秘密,p。 74、28 在 Google 图书上获得 5 星评价?
【问题讨论】:
“所有人”?那个“大家”是谁? 我调整了这个问题,见上文。谢谢:) 目前还不清楚declaration
与operator precedence
有什么关系。这些是完全不同且不相关的术语。你确定你在这里使用了正确的术语吗?您在问题开头的陈述 “我已经弄清楚如何阅读 C 声明......解释一直是对 C 中表达式和运算符优先级的引用” 没有什么意义! !!
让我们做一些逻辑归纳:如果一家公司费心向您询问复杂的 C 类型声明,那么他们可能认为它们对他们的代码库很重要。然后,你应该 RUN RUN RUN 而不是申请那份工作,因为显然代码库很糟糕。
@barak manos 不,这没有什么意义,尽管它可能会产生误导。有一句话说“我已经解决了。”,然后是另一个说“有一个解释”。但这并不意味着,我已经用那个具体的解释来解决了。
【参考方案1】:
这是因为声明反映了使用。
在声明的语法中,声明符被分成指针部分,后跟直接声明符,其中应用了数组形成[]
和函数形成()
构造,因此形成数组或函数类型比形成指针类型具有更高的优先级。
并且,反映这一点,在表达式的语法中,后缀运算符 []
和 ()
的优先级高于前缀一元运算符 *
。
这意味着当我们看到int *f()
时,我们知道这是一个返回指向int
的指针的函数,因为*f()
给出了一个int
类型的值;同样我们知道char (*g)()
是一个指向返回char
的函数的指针,因为(*g)()
必须给出char
类型的值。
这就是允许错误进入附录 A 的原因;预计没有人会阅读它,因为应用声明 - 反映 - 使用规则会给出正确的结果并且更容易应用。
【讨论】:
嘿-我进入只写存储器的销售业务并在这里做广告!然后,人们终于知道在哪里写“Appendices no one is expected to read”。以上是关于通过 K&R 的 C 书籍第 2 版理解 C 声明的主要内容,如果未能解决你的问题,请参考以下文章