C语言复杂声明详解

转载 2013年12月04日 17:01:02
C语言所有复杂的指针声明,都是由各种声明嵌套构成的。如何解读复杂指针声明呢?右左法则是一个既著名又常用的方法。不过,右左法则其实并不是C标准里面的内容,它是从C标准的声明规定中归纳出来的方法。C标准的声明规则,是用来解决如何创建声明的,而右左法则是用来解决如何辩识一个声明的,两者可以说是相反的。右左法则的英文原文是这样说的:The right-left rule: Start reading the declaration from the innermost parentheses, go right, and then go left. When you encounter parentheses, the direction should be reversed. Once everything in the parentheses has been parsed, jump out of it. Continue till the whole declaration has been parsed.这段英文的翻译如下:右左法则:首先从最里面的圆括号看起,然后往右看,再往左看。每当遇到圆括号时,就应该掉转阅读方向。一旦解析完圆括号里面所有的东西,就跳出圆括号。重复这个过程直到整个声明解析完毕。笔者要对这个法则进行一个小小的修正,应该是从未定义的标识符开始阅读,而不是从括号读起,之所以是未定义的标识符,是因为一个声明里面可能有多个标识符,但未定义的标识符只会有一个。现在通过一些例子来讨论右左法则的应用,先从最简单的开始,逐步加深:int (*func)(int *p);首先找到那个未定义的标识符,就是func,它的外面有一对圆括号,而且左边是一个*号,这说明func是一个指针,然后跳出这个圆括号,先看右边,也是一个圆括号,这说明(*func)是一个函数,而func是一个指向这类函数的指针,就是一个函数指针,这类函数具有int*类型的形参,返回值类型是int。int (*func)(int *p, int (*f)(int*));func被一对括号包含,且左边有一个*号,说明func是一个指针,跳出括号,右边也有个括号,那么func是一个指向函数的指针,这类函数具有int *和int (*)(int*)这样的形参,返回值为int类型。再来看一看func的形参int (*f)(int*),类似前面的解释,f也是一个函数指针,指向的函数具有int*类型的形参,返回值为int。int (*func[5])(int *p);func右边是一个[]运算符,说明func是一个具有5个元素的数组,func的左边有一个*,说明func的元素是指针,要注意这里的*不是修饰func的,而是修饰func[5]的,原因是[]运算符优先级比*高,func先跟[]结合,因此*修饰的是func[5]。跳出这个括号,看右边,也是一对圆括号,说明func数组的元素是函数类型的指针,它所指向的函数具有int*类型的形参,返回值类型为int。int (*(*func)[5])(int *p);func被一个圆括号包含,左边又有一个*,那么func是一个指针,跳出括号,右边是一个[]运算符号,说明func是一个指向数组的指针,现在往左看,左边有一个*号,说明这个数组的元素是指针,再跳出括号,右边又有一个括号,说明这个数组的元素是指向函数的指针。总结一下,就是:func是一个指向数组的指针,这个数组的元素是函数指针,这些指针指向具有int*形参,返回值为int类型的函数。int (*(*func)(int *p))[5];func是一个函数指针,这类函数具有int*类型的形参,返回值是指向数组的指针,所指向的数组的元素是具有5个int元素的数组。要注意有些复杂指针声明是非法的,例如:int func(void) [5];func是一个返回值为具有5个int元素的数组的函数。但C语言的函数返回值不能为数组,这是因为如果允许函数返回值为数组,那么接收这个数组的内容的东西,也必须是一个数组,但C语言的数组名是一个右值,它不能作为左值来接收另一个数组,因此函数返回值不能为数组。int func[5](void);func是一个具有5个元素的数组,这个数组的元素都是函数。这也是非法的,因为数组的元素除了类型必须一样外,每个元素所占用的内存空间也必须相同,显然函数是无法达到这个要求的,即使函数的类型一样,但函数所占用的空间通常是不相同的。作为练习,下面列几个复杂指针声明给读者自己来解析,答案放在第十章里。int (*(*func)[5][6])[7][8];int (*(*(*func)(int *))[5])(int *);int (*(*func[7][8][9])(int*))[5];实际当中,需要声明一个复杂指针时,如果把整个声明写成上面所示的形式,对程序可读性是一大损害。应该用typedef来对声明逐层分解,增强可读性,例如对于声明:int (*(*func)(int *p))[5];可以这样分解:typedef int (*PARA)[5]; typedef PARA (*func)(int *); 例子:void (*signal(int signr, void (*handler)(int)))(int); ================================================ handler是一个函数指针,指向参数为单参数int,返回类型void的函数 signal是一个函数指针、这个函数指针指向一个参数为一个int型和一个handler型的指针、返回值是一个指向参数为int、返回值是void的函数的指针的指针。总结一下: 这个复杂的声明可以用下面2种比较简单的型式表达出来,如下: 第一种型式如下: typedef void (*handler_pt)(int); handler_pt signal1(int signum,handler_pt ahandler); 第二种型式如下: typedef void handler_t(int); handler_t* signal2(int signum, handler_t* ahandler); ------------------------------------------------------ 以上这两种形式结果是等价的,但也有区别,第一种形式定义的是函数指针类型, sizeof(handler_pt)=4//borland c++ 5.6.4 for win 32,windos xp 32 platform 第二种形式定义的是函数类型,如果对他使用sizeof(handler_t)会提示: sizeof may not be applied to a function 测试程序如下: //void (*signal(int signum,void(*handler)(int)))(int); #include void handler(int num){ std::cout < < "This is " < <num < < "# hander! " < <std::endl; } typedef void (*handler_pt)(int); typedef void handler_t(int); handler_pt signal1(int signum,handler_pt ahandler){ ahandler(signum); std::cout < < "set " < <signum < < "# handler " < <std::endl; return ahandler; } handler_t* signal2(int signum, handler_t* ahandler){ ahandler(signum); std::cout < < "set " < <signum < < "# handler " < <std::endl; return ahandler; } int main(int argc,char** argv){ std::cout < < "sizeof(handler_pt)= " < <sizeof(handler_pt) < <std::endl; //std::cout < < "sizeof(handler_t)= " < <sizeof(handler_t) < <std::endl; std::cout < < "函数指针类型: " < <std::endl; signal1(5,handler)(6); std::cout < < "函数类型: " < <std::endl; signal2(5,handler)(6); }

C语言中的复杂声明和定义,以及如何使用typedef进行简化

在阅读Linux的内核代码是经常会遇到一些复杂的声明和定义,诸如:         (1)  void * (* (*fp1) (int)) [10];         (2)  float (* (...
  • skywalker_leo
  • skywalker_leo
  • 2015年09月21日 10:12
  • 1929

C语言难点专题——复杂的函数声明

类似void(*signal(int, void(*)(int)))()的说明, 经典或者不经典的书籍, 都有过解读, 《C专家编程中》, 设定了一套长长的解读规则, 记住它恐怕绝非易事, 后面终于在...
  • ostrichmyself
  • ostrichmyself
  • 2010年03月21日 09:55
  • 2250

C语言复杂指针理解

本文提供了一种分析C语言中复杂指针的方法,即代入法(笔者暂且命名为此). 希望这篇文章对那些因C语言复杂指针迷糊的开发者以帮助....
  • QZFZZ
  • QZFZZ
  • 2014年12月22日 11:29
  • 1071

如何分析复杂的C语言声明

1. 理解C语言声明的规则声明从它的名字开始读取,然后按照优先级顺序以此读取优先级从高到低依次是:声明中被括号扩起来的那部分后缀操作符括号()表示这是一个函数放括号[]表示这是一个数组前缀参数操作符星...
  • lujun9972
  • lujun9972
  • 2015年05月26日 07:34
  • 374

C语言复杂声明的解析

C语言复杂声明的解析(刘爱贵 Aiguille.LIU)  C语言是一种通用的程序设计语言,它与UNIX系统之间具有非常密切的联系,C语言是在UNIX系统上开发的,并且,无论是UNIX系统本身还是运行...
  • liuben
  • liuben
  • 2008年04月10日 18:13
  • 2506

理解c语言复杂声明

我们在工作中很少会声明类型复杂的变量,但是面试或者其他的情况还是需要用到的,下面讲述如何用简单的方法理解复杂声明。 c语言的声明的原则是 变量的类型和变量的取值运算(取得变量的值或者是调用函数指针执...
  • codesnail
  • codesnail
  • 2011年09月28日 13:09
  • 327

理解C语言中指针的声明以及复杂声明的语法

昨天刚把《C程序设计语言》中“指针与数组”章节读完,终于把心中的疑惑彻底解开了。现在记录下我对指针声明的理解,顺便说下如何在C语言中创建复杂声明以及读懂复杂声明。...
  • qq_28205153
  • qq_28205153
  • 2016年04月01日 23:51
  • 2805

C语言中变量的复杂声明和定义

我们知道:任何C语言变量的声明都由两部分组成:类型以及一组类似表达式的声明符。一旦我们知道如何声明一个给定类型的变量,那么该类型的类型转换符就很容易得到:只需要把声明中的变量名和末尾的分号去掉,再将剩...
  • GHX05130319
  • GHX05130319
  • 2015年05月08日 09:17
  • 1207

C语言复杂声明

char *f(); //f: function re char *(*pf) ();
  • persist_1
  • persist_1
  • 2014年07月27日 23:10
  • 424

c语言数组一些重要讲解

上面这个选择排序法编译运行时间是0.25秒gcc编译器 下面看看用指针怎么来进行操作 上面就是指针的操作方法 下面我们来看一下冒泡排序法,还是用两种方法来做 ...
  • Pxx520Tangtian
  • Pxx520Tangtian
  • 2016年12月26日 03:39
  • 216
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:C语言复杂声明详解
举报原因:
原因补充:

(最多只允许输入30个字)