看这个:

C指针声明解读之左右法则
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.

这段英文的翻译如下:

右左法则:首先从最里面的圆括号内未定义的标识符开始阅读看起,然后往右看,再往左看。每当遇到圆括号时,就应该掉转阅读方向。一旦解析完圆括号里面所有的东西,就跳出圆括号。重复这个过程直到整个声明解析完毕。

  总之对声明进行分析,最根本的方法还是按优先级和结合性来类比替换,从那些最基本的声明进行类比,简化,从而进行理解。下面分析几个例子,来具体阐述如何使用这种方法。

#1:int* (*a[5])(int, char*);

  首先看到标识符名a,"[]"优先级大于"*",a与"[5]"先结合。所以a是一个数组,这个数组有5个元素,每一个元素都是一个指针,指针指向"int* (int, char*)",很明显,指向的是一个函数,这个函数参数是"int, char*",返回值是"int*"。OK,结束了一个。:)

#2:void (*b[10]) (void (*)());

  b是一个数组,这个数组有10个元素,每一个元素都是一个指针,指针指向一个函数,函数参数是"void (*)()"【注:这也是一个函数指针, 参数为空,返回为void】,返回值是"void"。完毕!

#3:int(*)() (*c)[9];

   c是一个指针,指针指向一个数组,这个数组有9个元素,每一个元素都是"int(*)()"(也即一个函数指针,指向一个函数,这个函数的参数为空,返回值是int型)。

#4:int (*(*d)[5])(int *);

(*d)------指针;
  (*d)[5]------这个指针指向一个数组;
  *(*d)[5]------这个数组中每个元素都是指针类型;
  int (int *)------ 什么类型的指针?这个类型的。
    
    
#5:int (*(*e)(int *))[5];  
  *e-----向右遇到括号,向左遇到*,说明e是个指针,啥指针呢?
  (*e)(int *)------跳出括号向右遇到(int *),说明这个指针是个函数指针,形参为int*, 返回值为何?且听下回分解:);
  *(*e)(int *)------返回值为何?向右遇到括号,再向左,喔,遇到*了,那就是返回了一个指针了。啥指针呢? 同样地,下回分解;
  (*(*e)(int *))[5]-------向右遇到[],说明那是个指向数组的指针,是啥数组呢?不急,慢慢来;
  int (*(*e)(int *))[5]-------向左遇到int,喔,明白了,就是个简单的整型数组。OVER

当然实际当中,当需要声明一个复杂指针时,如果把整个声明写成上面所示的形式,对程序可读性将是一个巨大损害。谁要是写出这样BT的指针声明,那就真是丢rp了,估计会被骂死!。
  还是用typedef来对声明逐层分解替换下吧,增强可读性。

例如对于上面的声明:int (*(*func)(int *))[5]; 可以这样分解:
  typedef int (*pArr)[5];  
  typedef pArr (*func)(int *);  
  这样就容易读得多了啊!

再看看这个啥意思? typedef int (* (* (*FUNC)(int *) )[5] )(int *); ---- 晕了吧。

其实typedef int (* (* (*FUNC)(int *) )[5] )(int *);  
  等价与下面的:)

typedef int (*PF)(int *);

typedef PF (*PARRAY)[5];

typedef PARRAY (*FUNC)(int *);

(*(void (*)())0)();------->这个呢?
  按左右法则:
  (void (*)()) -----是一个返回值为void,参数为空的函数指针原型。
  (void (*)())0-----把0强转成一个返回值为void,参数为空的函数指针,指针指向的地址为0.
  *(void (*)())0-----前面加上*表示整个是一个返回值为void的函数的名字
  (*(void (*)())0)()------这当然就是一个函数调用了。

再typedef化简下:
  typedef void (*pf)();
  (*(pf)0)();

char (*(*p[3])( int ))[5] 等等一系列 左右法则的更多相关文章

  1. char 数组和 int 之间转化

    上周工作结束,来到斯凯网络也将近半个月来. 没有新人的感念,最多的是将自己当作一个战士. 废话不多说,直接入正题,在没有仔细考虑问题之前我们总会 觉得:这尼玛的有毛线难度啊,不就是一个 int 转为c ...

  2. C++ char*,const char*,string,int 的相互转换

    C++ char*,const char*,string,int 的相互转换   1. string转const char* string s ="abc";const char* ...

  3. 34 char类型转换为int类型

    #include<iostream> #include<cstdlib > using namespace std; int main() { char a=101; int ...

  4. int main(int argc,char *argv[])与int main(int argc,char **argv)区别?

    int main(int argc,char *argv[])与int main(int argc,char **argv)区别? 这两种是一个等价的写法 而int main(int argc,cha ...

  5. MySql 时间戳存char还是存int?

    一次小事故,让我对时间戳存char还是存int有了深刻的印象. 生产环境的sql条件涉及到时间戳字段的大小比较(between and),当时设计的时间戳类型是char(10),结果当数据量达到200 ...

  6. error C2556: 'const char &MyString::operator [](int)' : overloaded function differs only by return type from 'char &MyString::operator [](int)'

    char & operator[](int i);const char & operator[](int i);/*const char & operator(int i);* ...

  7. char * const * (*a) (int b)

    char * const * (*a) (int b), 按照c++ program language的读法,从右往左读,* 读作pointer to 把(*a) (int b看作整体, (*a) ( ...

  8. char类型和int类型之间的转换

    在视屏课程第二章里,我们已经学习了一些常用的数据类型转换.然而,有一些时候我们会经常会遇到将char类型转换成int类型,或者需要将int类型转换为char类型的情况. 这里,我们来探讨一下这种不常用 ...

  9. (C语言)char类型与int类型相加

    #include <stdio.h> int main(void) { ; ; int c = a + b; a += b; printf("c=%d",c); //p ...

随机推荐

  1. Redrain仿酷狗音乐播放器开发完毕,发布测试程序

    转载请说明原出处,谢谢~~ 从暑假到现在中秋刚过,我用duilib开发仿酷狗播放器大概经历了50天.做仿酷狗的意图只是看原酷狗的界面比较漂亮,想做个完整一些的工程来练习一下duilib.今天把写好的程 ...

  2. asp.net MVC 中@Html.Partial,@Html.Action,@Html.RenderPartial,@Html.RenderAction区别

    @Html.Action:需要有对应的Action,并且Action方法有返回值.(注:处理完业务逻辑同时,也需要返回所需值) @{Html.RenderAction}:需要有对应的Action,Ac ...

  3. 在ubuntu下配置android开发环境

    http://developer.android.com/sdk/installing/index.html 基本上上面官网的链接可以解决所有问题,但是具体在安装过程中还是有一些坑. 说说具体流程 1 ...

  4. Polymer——Template

    Polymer Template 一.Ta的简介 template是polymer element中一个重要的组成部分,主要有两种使用目的,一是构建Shadow Dom,二是用于数据绑定和视图渲染. ...

  5. Android版本判断

    尽管Android向下兼容不好,但是一个程序还是可以在多个平台上跑的.向下兼容不好,接口改变,新的平台上不能用旧的API,旧的平台更不可能用新的API,不等于一个平台需要一个APK.可以在高版本的SD ...

  6. storm的安装配置

    一.安装Zookeeper 1.设置.profile文件: export ZOOKEEPER_HOME=/home/hadoop/streamdata/zookeeper-3.4.5-cdh4.5.0 ...

  7. Hold住:坚持的智慧

    这类励志的书读完时,感觉很激励人,可读完后总觉得空空的.同样这本书读完后没特别的感觉(也许书中的思想已影响了我,只是目前还说不太清楚),只感觉有些句子很有感觉,做个汇总: 1.      荀子有言:“ ...

  8. Intellij IDEA Maven创建web项目

    Intellij IDEA在创建java webapp的时候没有那么人性化,新手使用会处处碰壁.特此记录! 一.File--New--project 二.Next--输入GroupId.Artifac ...

  9. 《Java数据结构与算法》笔记-CH4-3用栈实现分隔符匹配

    import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; /** * 利 ...

  10. SCAU 1138 代码等式

    1138 代码等式 时间限制:500MS  内存限制:65536K提交次数:59 通过次数:21 题型: 编程题   语言: 无限制 Description 一个代码等式就是形如x1x2...xi=y ...