《征服 C 指针》笔记6:练习——挑战那些复杂的声明

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

在 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 代表“指向信号处理函数的指针”这个类型。

时间: 2024-10-23 08:41:19

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

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

一.混乱的声明——如何自然地理解 C 的声明? 通常,C 的声明 int hoge; 这样,使用“类型 变量名;”的形式进行书写. 可是,像“指向 int 的指针”类型的变量,却要像下面这样进行声明: int *hoge_p; 似乎这里声明了一个名为 *hoge_p 的变量,而实际上,这里声明的变量是 hoge_p,hoge_p 的类型是“指向 int 的指针”. 因为这种声明方式不太好理解,所以有人提出将 * 靠近类型这一侧进行书写,如下: int* hoge_p; 的确,这种书写方式符号“类

C和指针笔记 3.6链接属性

链接属性决定如何处理在不同文件中出现的标识符.标识符的作用域也它的链接属性有关,但这两个属性并不相同. 没有链接属性的标识符(none)总是被当作单独的个体,也就是说该标识符的多个声明被当作独立不同的实体. internal链接属性的标识符在同一个源文件内的所有声明中都指同一个实体,但位于不同源文件的多个声明则分属不同的实体.最后,属于external链接属性的标识符不管声明多少次.位于几个源文件都表示同一个实体. 图3.2的程序骨架通过展示名字声明的所有不同方式,描述了链接属性.在缺省情况下,

C和指针笔记 3.7 存储类型

变量的破碎类型是指存储变量值的内存类型.变量的存储类型决定变量何时创建.何时销毁以及它的值将保持多久. 有三个地方可以用于存在变量:普通内存.运行时堆栈.硬件寄存器. 变量的缺省存储类型取决于它的声明位置.凡是在任何代码块之外声明的变量问题存储于静态内存中,也就是不属于堆栈的内存,这类变量称为静态变量.对于这类变量,你无法为它们指定其他存储类型.静态变量在程序运行之前创建,在程序的整个执行期间始终存在.它始终保持原先的值,除非给它赋一个不同的值或者程序结束. 在代码块内部声明的变量的缺省存储类型

C和指针笔记 3.8 static关键字

当用于不同的上下文环境时,static关键字具有不同的意思. 当它用于函数定义时,或用于代码块之外的变量声明时,static关键字用于修改标识符的链接属性,从external改为internal,但标识符的存储类型和作用域不受影响.用这种方式声明的函数或变量只能在声明它们的源文件中访问. 当它用于代码块内部的变量声明时,static关键字用于修改变量的存储类型,从自动变量修改为静态变量,但变量的链接属性和作用域不受影响.用这种方式声明的变量在程序执行之前创建,并在程序的整个执行期间一起存在,而不

征服C指针-C的变量种类

C语言的变量具有区间性的作用域.在开发一些小程序的时候也许我们并不在意作用域的必要性.可是,当你书写几万行,甚至几十万行的代码的时候,没有作用域肯定是不能忍受的.C语言有如下三种作用域. 1. 全局变量 在函数之外声明的变量,默认地会成为全局变量.全局变量在任何地方都是可见的.当程序被分割为多个源代码文件进行编译时,声明为全局变量的变量也是可以通过关键字extern从其他源代码文件中引用的. 2. 文件内部的静态变量 就算对于像全局变量那样呗定义在函数外面的变量,一旦添加了static,作用域就

Effective c++(笔记) 之 类与函数的设计声明中常遇到的问题

1.当我们开始去敲代码的时候,想过这个问题么?怎么去设计一个类? 或者对于程序员来说,写代码真的就如同搬砖一样,每天都干的事情,但是我们是否曾想过,在c++的代码中怎么样去设计一个类?我觉得这个问题可比我们"搬砖"重要的多,大家说不是么? 这个答案在本博客中会细细道来,当我们设计一个类时,其实会出现很多问题,例如:我们是否应该在类中编写copy constructor 和assignment运算符(这个上篇博客中已说明),另外,我们是让编写的函数成为类的成员函数还是友元还是非成员函数,

读书笔记《征服C指针》----C的声明是这样解读的

解读C的声明的最好方法是用英语来阅读,道理很简单,因为C语言是美国人发明的. 为了把问题变得更简单,在这里暂不考虑const和volatile.接下来遵循以下步骤来解释C的声明. 首先着眼于标识符(变量名或者函数名). 从距离标识符最近的地方开始,依照优先顺序解释派生类型(指针.数组.和函数).优先顺序说明如下: 用于整理声明内容的括弧. 用于表示数组的[],用于表示函数的(). 用于表示指针的*. 解释完成完成派生类型,使用“of”.“to”.“returning”将它们连接起来. 最后,追加

c指针 --笔记2返回指针值的函数

返回指针值的函数 一般带回指针值的函数,定义形式为: int *a (int x, int y); 看这个经典案例: #include <stdio.h> int main(int argc, char const *argv[]) { double score[][4] = {{60.0, 70.0, 80.5, 20.1}, {60.0, 70.0, 80.5, 21.1}, {60.0, 70.0, 80.5, 22.1}}; double *search(double(*pointer

c++指针 笔记

我们定义一个指针就一定要用他保存一个内存地址,加入我们不这样做,那么该指针就是一个失控指针他可以指向任何地址,并且对该地址的数值进行修改或删除,后果是非常可怕的解决办法是将该指针初始化为0,即p = 0:该语句是将p所保存的地址清零,(即让p指向00000000这个地址,这个地址是不会存放任何数据的,因此我们对它进行的任意操作都不会产生严重后果)这样p就不会因为我们的疏忽而修改它指向的地址(随机)的值 由于指针类型不同决定了指针的运算方式不同,所以我们不能将一种类型的指针赋给另一种类型的指针 可