`
dbcman
  • 浏览: 16775 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

如何理解复杂的声明

    博客分类:
  • C
 
阅读更多

这里说的声明,不光适用于C/C++,其他的一些语言也能适用。

与java和C#等不同,声明和定义在C/C++中有着比较明显的区别:声明仅仅是介绍名字(introduce names),而定义则会为该名字分配相应的空间。打个通俗的比喻:声明就是你在谈话中提到某个人的名字,而定义就是把你提到的这个人带到谈话的人群中来,让大家见识一下他/她是什么样子。

这里主要介绍声明。
在C中,声明的形式为(dcl是declaration的简写):
dcl: optional *'s direct-dcl(含有可选"*"的direct-dcl)
direct-dcl name
                (dcl)
                direct-dcl()
                direct-dcl[optional size] 
根据该规则进行逆向解析,就可以得到正确的声明。简化一下:“TypeName Declarator;”其中,Declarator就是声明中的那个名字。当你遇到任何你不能理解的声明时,这个法则就是救命稻草。最简单的例子:
int aInt;
这里,int是TypeName,aInt是Declarator。
再说明一下结合紧密度。在声明/定义变量时,可以使用一些修饰比如“*”,“[]”,“()”等。“()”(非函数声明中的“()”)具有最高的紧密度,其次才是函数和数组的“()”和“[]”。
没有“*”的声明称为直接声明(direct-dcl),而有“*”称为声明(dcl)。直接声明要比声明结合的紧。分解声明时,先读出结合紧的。在这里,我把direct-dcl称为更紧的结合,它比dcl结合得紧。
最后,需要你用英语来读出这个声明。对于“[]”,应该读成array of。
对于复杂的定义,可以将其分解。比如“T (*p)()”可以分解成“T D1()”,D1读作:function returning T。其中D1是*p。那么该声明应该读成:p is a poniter to。二者合在一起,就变成了p is a pointer to function returning T,即:p是指向返回T类对象的函数的指针。

再看一个稍微复杂的示例:
T (*pfa[])();
根据dcl和direct-dcl,可以分解成T1 D1(因为结合紧密度),T1, 也就是T (),那么应该读作:
D1 is function returning T。
D1又可以写成T2 D2,其中T2是T1 [],可以分解成T1 D2[],读作:
array of D2 function returning T。
D2是指针,读作:pointers to。那么整个“T (*pfa[])();”应该读作:
pfa is an array of pointers to function returning T,即:pfa是个存放指向返回T类对象函数的指针的数组。

换种方式看,在这个例子中,pfa是名字,T(*[])()是类型。将(*pfa[])视为一体(direct-dcl),称为D1,那么可以写成T D1(),function returning object of T。在D1中,将*pfa视为一体(dcl),称为D2,那么*pfa[]应该是D2[](direct-dcl),array of D2。合起来就是array of D2 function returning object of T。D2是*pfa(dcl),替换到前面这句话,结果就是array of pointers to function returning object of T。

有了这些说明,可以试着做一下下面的题,看看自己是否真的理解了:

char **argv
    argv:  pointer to pointer to char
int (*daytab)[13]
    daytab:  pointer to array[13] of int
int *daytab[13]
    daytab:  array[13] of pointer to int
void *comp()
    comp: function returning pointer to void
void (*comp)()
    comp: pointer to function returning void
char (*(*x())[])()
    x: function returning pointer to array[] of
    pointer to function returning char
char (*(*x[3])())[5]
    x: array[3] of pointer to function returning
    pointer to array[5] of char
有了这个,就很容易理解下面这两个typedef:
typedef void (*disp)(int);
typedef void (*signal(int, disp))(int);

在C++中,规则比C要复杂一些。不过,基本思想保持不变,按照C的原则来理解复杂的声明,基本上就能满足要求了。没有在这里列出C++的规则一方面是因为太广,不能覆盖全;另一个原因就是,按照C的规则来就足够了,毕竟C++要与C兼容。

这里讨论的仅仅是声明,不涉及到类型的signature,因此相对来说还是比较简单的。

参考:
The C programming Language, by Brian W. Kernighan and Dennis M. Ritchie
The C++ programming Language, by Bjarne Stroustup
 
Copyleft (C) 2007-2009 raof01.
本文可以用于除商业外的所有用途。此处“用途”包括(但不限于)拷贝/翻译(部分或全部),不包括根据本文描述来产生代码及思想。若用于非商业,请保留此 权利声明,并标明文章原始地址和作者信息;若要用于商业,请与作者联系(raof01@gmail.com),否则作者将使用法律来保证权利。

分享到:
评论

相关推荐

    如何理解c和c++的复杂类型声明.pdf

    7. **解析复杂声明**:C和C++中的K&R(Kernel Normal Form)规则是理解复杂声明的一种方法。从右向左读取声明,每次遇到星号(*),就添加一个指针,遇到方括号([])就添加一个数组,遇到圆括号()就表示函数。这样可以...

    如何理解c和c ++的复杂类型声明

    本文旨在逐步解析这类复杂声明,并通过一系列示例帮助读者掌握理解复杂声明的方法。 #### 基础类型声明 首先,我们从最简单的类型声明开始。例如: ``` int n; ``` 这是一条非常简单的声明,意味着`n`是一个整型...

    如何理解和应用C语言中的复杂声明

    4 优先级和结合性在C语言中,类型说明符、指针运算符、数组运算符和函数运算符的优先级和结合性是理解复杂声明的关键。类型说明符的优先级最高,接着是函数运算符,然后是数组运算符,最后是指针运算符,它们都是从...

    如何理解C和C++的复杂的声明

    如何理解C和C++的复杂的声明如何理解C和C++的复杂的声明如何理解C和C++的复杂的声明如何理解C和C++的复杂的声明如何理解C和C++的复杂的声明如何理解C和C++的复杂的声明如何理解C和C++的复杂的声明如何理解C和C++的...

    C语言复杂声明xiaoyi

    下面我们将详细探讨如何解析和理解C语言的复杂声明。 首先,我们遵循声明中的优先级规则,它决定了我们读取声明的顺序:名称、()、[]、*。这意味着在声明中,我们首先找到变量的名称,然后是括号,接着是方括号,...

    教你理解复杂的C-C++声明.txt

    ### 教你理解复杂的C-C++声明 在学习C或C++编程语言的过程中,理解复杂的类型声明是一项重要的技能。本文将深入探讨各种复杂的声明,并解释它们的实际意义。 #### 基础概念 在开始之前,我们需要了解一些基本的...

    如何理解C和C++复杂类型声明

    本文旨在逐步解析这类复杂声明,并通过一系列由简入繁的例子帮助读者更好地理解和掌握。 #### 基础类型声明 首先,我们从最基础的类型声明开始了解: 1. **int n;** 这是最常见的声明方式,表示`n`是一个整型...

    如何理解c和c++的复杂类型声明

    ### 如何理解C和C++中的复杂类型声明 在学习C和C++的过程中,经常会遇到一些复杂的...记住,虽然理解复杂的类型声明是一项重要的技能,但在实际编程中应尽可能避免使用过于复杂的声明,以保持代码的清晰性和可维护性。

    理解复杂的C++声明

    【理解复杂的C++声明】 在C++编程中,声明复杂变量和类型是常见的挑战,特别是涉及到指针、引用、const修饰符以及typedef等概念时。本文旨在帮助开发者逐步理解并解析复杂的C++声明。 首先,从基础开始。一个简单...

    如何理解c和c_++的复杂类型声明.doc

    了解了这些基本规则后,可以使用"右左法则"来解析复杂声明。从变量名开始,向右读取直到遇到类型名,这告诉你是变量的类型。然后从类型名开始,向左读取,处理所有的指针(*)、引用(&)、数组[]和const修饰符,直到...

    复杂函数申明解析

    右左法则是理解复杂声明的黄金法则。它建议从变量名开始,向左看第一个符号,决定这个符号是什么(例如`*`表示指针,`&`表示引用),然后向右看第一个符号,决定声明的下一个部分,以此类推,直到完成整个声明的解析...

    教你理解复杂的C&Cpp声明

    在学习C或C++语言的过程中,经常会遇到一些让人感到困惑甚至头疼的复杂声明。例如,`int * (* (*fp1) (int) ) [10];` 这样的声明对于初学者来说几乎是不可读的。本文将分步骤地引导你理解这类复杂的声明,并通过引入...

    教你理解复杂的C声明.txt

    ### 教你理解复杂的C声明 对于初学者来说,理解C语言中的复杂声明是一大挑战。本文将通过解析几个典型的复杂声明案例,帮助读者更好地掌握这一技能。 #### 1. 多级指针声明 首先来看一个较为复杂的声明示例: ```...

    教你理解复杂的C_C++声明

    ### 教你理解复杂的C/C++声明 在学习C或C++编程时,理解复杂的声明是必不可少的一部分。本文将从几个具体的例子出发,逐步解析如何理解这些看似难以捉摸的声明,并帮助读者建立起清晰的认知框架。 #### 基础概念...

    初学者必备: 教你理解复杂的C++声明

    本文将由易到难,一步一步教会你如何理解这种复杂的C/C++声明。我们将从每天都能碰到的较简单的声明入手,然后逐步加入 const修饰符和typedef,还有函数指针,最后介绍一个能够让你准确地理解任何C/C++声明的“右左...

    教你理解复杂的C-C++声明

    本文将深入探讨如何解析和理解复杂的C/C++声明,帮助你解开那些看似混乱的语法迷宫。 首先,我们来看一个典型的复杂声明示例:“int * (* (*fp1) (int) )[10]”。这个声明定义了一个名为`fp1`的变量,它是一个函数...

Global site tag (gtag.js) - Google Analytics