通过 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 星评价?

【问题讨论】:

“所有人”?那个“大家”是谁? 我调整了这个问题,见上文。谢谢:) 目前还不清楚declarationoperator 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”。 在声明的语法中,声明符被分成一个指针部分,后跟一个直接声明符,其中应用了数组形成 [] 和函数形成 () 构造,所以形成一个数组或函数类型比形成一个指针类型具有更高的优先级。 唯一说明语法的顺序将定义优先级的语句在 §7... @polynomial_donut 这只是对读者的帮助;每个文法都有一组相关的优先规则,因此没有必要声明声明的文法意味着它自己的优先级。 @ecatmur 是的,我也在考虑这个问题,但是为什么 K&R 会努力隐含地给出另一组(尽管是等效的)规则来解释声明(请参阅我应用的规则... )? @polynomial_donut 另一组规则是什么?我所知道的只是语法和语法中的语义。

以上是关于通过 K&R 的 C 书籍第 2 版理解 C 声明的主要内容,如果未能解决你的问题,请参考以下文章

从 K&R 书中解释 malloc 的这种实现

K&R书练习4-2

推荐书籍 | 深入理解Java虚拟机(第2版)

一些常用的排序算法(C版)

优质的计算机专业书籍有哪些?

前端书籍推荐