应该是小试牛刀的时候了。

在 ANSI C 的标准库中,有一个 atexit()函数。如果使用这个函数,当程序正常结束的时候,可以回调一个指定的函数。

atexit()的原型定义如下:

int atexit(void (*func)(void));

1、首先着眼于标识符。

int atexit(void (*func)(void));

英语的表达为:

atexit is

2、解释用于函数的()。

int atexit(void (*func)(void));

英语的表达为:

atexit is function() returning

3、函数的参数部分比较复杂,所以先解析这部分。同样地, 先着眼于标识符。

int atexit(void (*func)(void));

英语的表达为:

atexit is function(func is) returning

4、因为有括号, 所以这里解释*。

int atexit(void (*func)(void));

英语的表达为:

atexit is function(func is pointer to) returning

5、解释用于函数的()。这里的参数还是比较简单的, 是 void(无参数) 。

int atexit(void (*func)(void));

英语的表达为:

atexit is function(func is pointer to function (void) returning) returning

6、解释类型指定符 void。这样就结束了 atexit 的参数部分的解释。

int atexit(void (*func)(void));

英语的表达为:

atexit is function(func is pointer to function(void) returning void) returning

7、解释数据类型修饰符 int。

int atexit(void (*func)(void));

英语的表达为:

atexit is function (func is pointer to function (void) returning void) returning int

8、翻译成中文……

atexit 是返回 int 的函数(参数是,指向返回 void 没有参数的函数的指针) 。

下面是一个更加复杂的例子。

标准库中有一个 signal()函数,它的原型声明如下,

void (*signal(int sig, void (*func)(int)))(int);

1、首先着眼于标识符。

void (*signal(int sig, void (*func)(int)))(int);

英语的表达为:

signal is

2、相比*, ()的优先顺序更高,所以先解释这部分。

void (*signal(int sig, void (*func)(int)))(int);

英语的表达为:

signal is function() returning

3、解释参数部分。这里有两个参数,第一参数是 int sig。

void (*signal(int sig, void (*func)(int)))(int);

英语的表达为:

signal is function(sig is int,) returning

4、着眼另外一个参数。

void (*signal(int sig, void (*func)(int)))(int);

英语的表达为:

signal is function(sig is int, func is) returning

5、因为有括号, 所以这里解释*。

void (*signal(int sig, void (*func)(int)))(int);

英语的表达为:

signal is function(sig is int, func is pointer to) returning

6、解释表示函数的(), 参数为 int。

void (*signal(int sig, void (*func)(int)))(int);

英语的表达为:

signal is function(sig is int, func is pointer to function(int) returning) returning

7、解释数据类型修饰符 void。

void (*signal(int sig, void (*func)(int)))(int);

英语的表达为:

signal is function(sig is int, func is pointer to function(int) returning void) returning

8、参数部分已经解释结束。接着因为有括号,所以这里解释*。

void (*signal(int sig, void (*func)(int)))(int);

英语的表达为:

signal is function(sig is int, func is pointer to function(int) returning void) returning pointer to

9、解释表示函数的(),参数为 int。

void (*signal(int sig, void (*func)(int)))(int);

英语的表达为:

signal is function(sig is int, func is pointer to function(int) returning void) returning pointer to function(int) returning

10、最后,添上 void。

void (*signal(int sig, void (*func)(int)))(int);

英语的表达为:

signal is function(sig is int, func is pointer to function(int) returning void) returning pointer to function(int) returning void

11、翻译成中文……

signal 是返回“指向返回 void,参数为 int 的函数的指针”的函数,它有两个参数, 一个是 int,另一个是“指向返回 void 参数为 int 的函数的指针”。

如果能读懂这种难度的声明,我想应该不会再有什么让你畏惧的 C 声明了。

下面的说明可能会让你对 C 语言感到更加不快。

signal()是用于注册信号处理(当中断发生时被调用的函数)的函数。此函数的返回值是之前注册的处理当前信号中断的函数。

也就是说,其中的一个参数和返回值,它们都是相同的类型——指向信号处理函数的指针。在一般的语言中,同样的表现模式出现两次并不会让你感到不适,但是解释 C 语言声明的过程是“一会儿向左一会儿向右”,因此,表示返回值的部分散落了在左右两侧。

此时,运用 typedef 可以让声明变得格外得简洁。

/*摘录于FreeBSD 的man page /
typedef void(sig_t)(int);
sig_t signal(int sig, sig_t func);

sig_t 代表“指向信号处理函数的指针”这个类型。

延伸阅读:

《征服 C 指针》摘录1:什么是空指针?区分 NULL、0 和 '\0'

《征服 C 指针》摘录2:C变量的 作用域 和 生命周期(存储期)

《征服 C 指针》摘录3:数组 与 指针

《征服 C 指针》摘录4:函数 与 指针

《征服 C 指针》摘录5:函数形参 和 空的下标运算符[]

《征服 C 指针》摘录6:解读 C 的声明

《征服 C 指针》摘录7:练习——挑战那些复杂的声明

《征服 C 指针》笔记6:练习——挑战那些复杂的声明的更多相关文章

  1. 《征服 C 指针》摘录6:解读 C 的声明

    一.混乱的声明——如何自然地理解 C 的声明? 通常,C 的声明 int hoge; 这样,使用“类型 变量名;”的形式进行书写. 可是,像“指向 int 的指针”类型的变量,却要像下面这样进行声明: ...

  2. 《征服 C 指针》摘录1:什么是空指针?区分 NULL、0 和 '\0'

    一.什么是空指针? 空指针 是一个特殊的指针值. 空指针 是指可以确保没有向任何一个对象的指针.通常使用宏定义 NULL 来表示空指针常量值. 空指针 确保它和任何非空指针进行比较都不会相等,因此经常 ...

  3. 《征服 C 指针》摘录2:C变量的 作用域 和 生命周期(存储期)

    在开发一些小程序的时候,也许我们并不在意作用域的必要性.可是,当你书写几万行,甚至几十万行的代码的时候,没有作用域肯定是不能忍受的. C 语言有如下 3 种作用域. 1.全局变量 在函数之外声明的变量 ...

  4. 《征服 C 指针》摘录3:数组 与 指针

    一.数组 和 指针 的微妙关系 数组 是指将固定个数.相同类型的变量排列起来的对象. 正如之前说明的那样,给指针加 N,指针前进“当前指针指向的变量类型的长度 X N”. 因此,给指向数组的某个元素的 ...

  5. 《征服 C 指针》摘录4:函数 与 指针

    一.指向函数的指针 函数名可以在表达式中被解读成“指向函数的指针”,因此,正如代码清单 2-2 的实验那样,写成 func 就可以取得指向函数的指针. “指向函数的指针”本质上也是指针(地址),所以可 ...

  6. 《征服 C 指针》摘录5:函数形参 和 空的下标运算符[]

    一.函数的形参的声明 C 语言可以像下面这样声明函数的形参: void func(int a[]) {     // ... } 对于这种写法,无论怎么看都好像要向函数的参数传递数组. 可是,在 C ...

  7. 《征服C指针》读书笔记

    本文同时发布在我的个人博客上,欢迎访问~ www.seekingdream.cn 在读完K&R之后,对C的认识就是指针.数组.网上的人们对指针也有些“敬而远之”的感觉.最近从同学处淘得< ...

  8. Fortran学习笔记:01 基本格式与变量声明

    Fortran学习笔记目录 01 基本格式与变量声明 格式 固定格式(Fixed Format):Fortran77 程序需要满足一种特定的格式要求,具体形式参考教材 自由格式(Free Format ...

  9. 《征服c指针》学习笔记-----统计文本单词数目的程序word_count

    1.程序的要求:对用户指定的英文文本文件(包括标准输入),将英文单词按照字母顺序输出到用户指定的文本文件中(包括标准输出),并且在各单词后面显示单词的出现次数. 2.模块设计: 主要分为:1.从输入流 ...

随机推荐

  1. 洛谷P1280 尼克的任务[DP]

    题目描述 尼克每天上班之前都连接上英特网,接收他的上司发来的邮件,这些邮件包含了尼克主管的部门当天要完成的全部任务,每个任务由一个开始时刻与一个持续时间构成. 尼克的一个工作日为N分钟,从第一分钟开始 ...

  2. quartz-1.8.5 Demo

    最近在研究Spring中的定时任务功能,最好的办法当然是使用Quartz来实现.对于一个新手来说,花了我不少时间,这里我写个笔记,给大家参考. 我使用的是Maven来管理项目,需要的Jar包我给大家贴 ...

  3. Python3实现TCP端口扫描

    在渗透测试的初步阶段通常我们都需要对攻击目标进行信息搜集,而端口扫描就是信息搜集中至关重要的一个步骤.通过端口扫描我们可以了解到目标主机都开放了哪些服务,甚至能根据服务猜测可能存在某些漏洞. TCP端 ...

  4. C#.NET 大型通用信息化系统集成快速开发平台 4.1 版本 - .NET商业化成品成熟各种数据权限的需求对应例子代码

    还是我上次提出的那个问题问题:假设一个订单表,1.角色A可以看自己的2.角色B可以看工作组的3.角色C可以看金额是1000元以下的(自定义条件是否可行?如果可以,请详细说明)4.角色D可以看整个部门的 ...

  5. 《Java学习笔记(第8版)》学习指导

    <Java学习笔记(第8版)>学习指导 目录 图书简况 学习指导 第一章 Java平台概论 第二章 从JDK到IDE 第三章 基础语法 第四章 认识对象 第五章 对象封装 第六章 继承与多 ...

  6. 【跟着子迟品 underscore】JavaScript 数组展开以及重要的内部方法 flatten

    Why underscore (觉得这一段眼熟的童鞋可以直接跳到正文了...) 最近开始看 underscore.js 源码,并将 underscore.js 源码解读 放在了我的 2016 计划中. ...

  7. C#基础系列——Attribute特性使用

    前言:上篇 C#基础系列——反射笔记 总结了下反射得基础用法,这章我们来看看C#的另一个基础技术——特性. 1.什么是特性:就博主的理解,特性就是在类的类名称.属性.方法等上面加一个标记,使这些类.属 ...

  8. 【深度分享】千团大战:看今天商业WiFi乱局及其破解之道

    不知道还有没有人记得起始于2010年的千团大战.从2010年初开始,第一家团购网站上线以来,到2011年底,团购网站的数量超过了5000家.当时就有很多媒体预言,2013年,团购的泡沫就将褪去,将有9 ...

  9. CCS 6新建TMS320F2812工程

    准备材料 CCS6 下载地址:http://www.ti.com/tool/ccstudio F2812的C语言头文件 下载地址:http://www.ti.com/lit/zip/sprc097 安 ...

  10. go 数据类型转换

    使用strconv 包 首先需要import strconv包 //string to int i,err := strconv.Atoi(str) // string to int64 i64,er ...