本文已迁移至:

http://www.danfengcao.info/c/c++/2014/02/25/howto-understand-complicated-declaration-of-c.html

C语言中有时会出现复杂的声明,比如

char * const * (*next) (); //这是个什么东东?

在讲复杂声明的分析方法前,先来个补充点。

C语言变量的声明始终贯彻两点

1.声明和使用的语法尽量保持一致

例如:

#include <iostream>
using namespace std; double (*fun)(double); //声明一个函数指针 int main(){
fun=sin;
doube reslut=(*fun)(0.5);//使用这个函数指针
...
}

2.声明语句不是的阅读不是按照从左往右的阅读顺序,而是要根据各个符号的优先级进行阅读的

这点非常重要!先列出C语言声明的优先级规则,再举个例子就能掌握求解方法了。

C语言声明的优先级规则

A 声明从它的名字开始读取,然后按照优先级顺序依次读取;

B 优先级从高到低依次是:

B.1 声明中被括号括起来的那部分;

B.2 后缀操作符:

括号()表示这是一个函数,而

放括号[]表示这是一个数组;

B.3 前缀操作符:星号*表示这是一个“指向...的指针”;

C 如果const和(或)volatile关键字的后面紧跟类型说明符(如int,long等),那么它作用于类型说明符。在其他情况下,它作用于关键字左边紧邻的指针星号。

需要强调的一个重要注意点是,对于优先级: () > [] > * 。

举例,用优先级规则分析C语言声明一例:

char * const * (*next) ();

按照规则解读 char * const * (*next) ();

首先,(*next) 表示next是一个指针,它指向某个东东;

根据B.2和最右边的括号,next指向一个函数;

根据B.3,第二个星号表示,该函数返回一个指针;

char * const是函数返回的指针所指向的类型;

char* 是字符指针,const修饰左边的星号,即字符指针是常量的,该指针不可修改(该指针指向的字符内容是可修改的);

综合地表述为,next是一个指针,它指向一个函数,该函数返回一个指针,该指针指向一个类型为char的常量指针。

还是不明白?再往下看就明白了!

#---------------------------------------------------------------------------------#

总结一下,分析复杂的C语言声明,要采用"由内而外,层层剥离”的策略。

从哪里开始剥?从语句的最左边的标志符开始剥(上例为从next开始)。

往哪个方向剥?依照C语言的优先级规则一层层剥。

#---------------------------------------------------------------------------------#

再举一例作详细说明:

char *(* c[]) (int **p);

第一步,char *(* c[10]) (int **p);  最左边的标志符是c,表示"c是一个什么东东";

第二步,char *(*  [10]) (int **p);  和[10]结合,表示"c是一个长度为10的数组";

第三步,char *(*        ) (int **p);  和*结合,表示"这个数组存放着指针";

第四步,char *             (int **p);  和(int **p)结合,表示"这个指针指向一个函数,函数的参数是二维指针";

第五步,char *                         ;  和 * 结合,表示"这个函数返回一个指针";

第六步,char              ; 这个指针指向一个字符;

把上面六步串起来,读作: c是一个数组[0..9],它存放着指针,指针指向的函数参数是一个二维指针返回值是指向字符的指针。完工!

#---------------------------------------------------------------------------------#

注1: 这个方法若理解了,什么指针数组和数组指针、指针函数和函数指针等等之类的区别都是小菜一碟了。

注2: 合法的声明中存在限制条件。如函数的返回值不能是一个函数,也不能是一个数组,所以像function()()和function()[]是非法的,不能出现。数组里面能存函数指针,但不能存函数,像int (* function[])()是合法的,function[]()则是非法的。

#---------------------------------------------------------------------------------#

参考文献

《C专家编程》, Peter Van Der Linden 著, 徐波 译

如何读懂复杂的C语言声明的更多相关文章

  1. 一篇文章读懂JSON

    什么是json? W3C JSON定义修改版: JSON 指的是 JavaScript 对象表示法(JavaScript Object Notation) JSON 是轻量级的文本数据交换格式,并不是 ...

  2. 一文读懂Redis常见对象类型的底层数据结构

    Redis是一个基于内存中的数据结构存储系统,可以用作数据库.缓存和消息中间件.Redis支持五种常见对象类型:字符串(String).哈希(Hash).列表(List).集合(Set)以及有序集合( ...

  3. 一文读懂Java动态代理

    作者 :潘潘 日期 :2020-11-22 事实上,对于很多Java编程人员来说,可能只需要达到从入门到上手的编程水准,就能很好的完成大部分研发工作.除非自己强主动获取,或者工作倒逼你学习,否则我们好 ...

  4. C#基础之IL ,轻松读懂中间代码IL 转载

    [No0000152]C#基础之IL,轻松读懂IL   先说说学IL有什么用,有人可能觉得这玩意平常写代码又用不上,学了有个卵用.到底有没有卵用呢,暂且也不说什么学了可以看看一些语法糖的实现,或对.n ...

  5. Java8 函数式【1】:一文读懂逆变

    Java8 函数式[1]:一文读懂逆变 禁止转载 pure function 协变 逆变 Java8 引入了函数式接口,从此方法传参可以传递函数了,有人说: 不就是传一个方法吗,语法糖! lambda ...

  6. 从Spring中学到的【1】--读懂继承链

    最近看了一些 Spring 源码,发现源码分析的文章很多,而底层思想分析的文章比较少,这个系列文章准备总结一下Spring中给我的启示,包括设计模式思想.SOLID设计原则等,涉及一些编程的基本原则, ...

  7. Gradle学习系列之三——读懂Gradle语法

    在本系列的上篇文章中,我们讲到了创建Task的多种方法,在本篇文章中,我们将学习如何读懂Gradle. 请通过以下方式下载本系列文章的Github示例代码: git clone https://git ...

  8. 如何快速读懂大型C++程序代码

    要搞清楚别人的代码,首先,你要了解代码涉及的领域知识,这是最重要的,不懂领域知识,只看代码本身,不可能搞的明白.其次,你得找各种文档:需求文档(要做什么),设计文档(怎么做的),先搞清楚你即将要阅读是 ...

  9. 如何解析复杂的C语言声明

    C语言中有时会出现复杂的声明,比如   char * const * (*next) (); //这是个什么东东?   在讲复杂声明的分析方法前,先来个补充点.   C语言变量的声明始终贯彻两点 :  ...

随机推荐

  1. 记录一则ORA-12154,ORA-12560解决过程

    应用服务器:Windows Server 2008 R2 Enterprise 故障现象:项目侧同事反映应用服务器上的程序连接数据库报错:ORA-12560: TNS: 协议适配器错误 1.故障重现 ...

  2. jquery兼容实验

    使用jquery时候,曾经遇到两个问题: 1.一个页面里,使用了很多基于jquery的前端ui库,但是各个库之间对jquery的依赖的版本不一样,有的依赖jquery1.4,jquery2.0用不了: ...

  3. 在Mac上开发使用yeoman构建Asp.net core项目并且实现分层引用

    1.Yeoman? yeoman是一个自动化脚手架工具.它提供很多generator,generator相当于VisualStudio的模板,用来初始化项目.更多的就不多说了,写一遍都写不完,自己看吧 ...

  4. WPF老矣,尚能饭否——且说说WPF今生未来(下):安心

    在前面的上.中篇中,我们已经可以看到园子里朋友的点评“后山见! WPF就比winform好! 激情对决”.看到大家热情洋溢的点评,做技术的我也很受感动.老实说,如何在本文收笔--WPF系列文章,我很紧 ...

  5. [转载]C/C++框架和库

    C/C++框架和库 装载自:http://blog.csdn.net/xiaoxiaoyeyaya/article/details/42541419 值得学习的C语言开源项目 Webbench Web ...

  6. Xamarin.Android之封装个简单的网络请求类

    一.前言 回忆到上篇 <Xamarin.Android再体验之简单的登录Demo> 做登录时,用的是GET的请求,还用的是同步, 于是现在将其简单的改写,做了个简单的封装,包含基于Http ...

  7. [Q&A] 应用程序清单生成失败

    当在 Silverlight 客户端属性里(如下图),添加"允许在浏览器外运行应用程序"和"在浏览器内运行时需要提升的信任"时, 图1 目录下会自动生成如下两个 ...

  8. 浅谈web网站架构演变过程

    前言 我们以javaweb为例,来搭建一个简单的电商系统,看看这个系统可以如何一步步演变.   该系统具备的功能:   用户模块:用户注册和管理 商品模块:商品展示和管理 交易模块:创建交易和管理 阶 ...

  9. 图解SQL的Join(转)

    对于SQL的Join,在学习起来可能是比较乱的.我们知道,SQL的Join语法有很多inner的,有outer的,有left的,有时候,对于Select出来的结果集是什么样子有点不是很清楚.Codin ...

  10. this上下文,以及通过call 、apply 实现继承

    上下文:this关键字通常指向当前函数的拥有者,把拥有者叫做执行上下文. this代表函数运行时自动生成的内部对象,只能在函数内部使用. 构造函数中的this 指 构造函数的实例对象.javascri ...