1. 声明和表达式
任何C变量的声明都由两部分组成:类型 + 一组类似表达式的声明符(declarator)。
声明符与表达式的相似之处:对它求值应该返回一个声明中给定类型的结果。
最简单声明单个变量
如 float f, g; 这个声明的含义是:对其求值时,表达式f和g的类型为浮点数类型,因为声明符和表达式的相似,所以可以在声明符中任意使用括号: float ( (f) );
同样的逻辑也适用于函数和指针类型的声明。
float ff( ); 的表达式ff( )求值结果是一个浮点数,也就是说,ff是一个返回值为浮点类型的函数。
float *pf; 这个声明的含义是*pf是一个浮点数,也就是说,pf是一个指向浮点数的指针。
以上形式在声明中可以组合起来,就像在表达式中进行组合一样。
float *g( ), (*h)( ); *g( )与(*h)( )是浮点表达式。因为( )优先级高于*,*g( )也就是*( g( ) ):g是一个函数,该函数的返回值类型为指向浮点数的指针。同理,可以得出h是一个函数指针,h所指向的函数的返回值为浮点类型。
2. 声明和类型转换
一旦我们知道了如何声明一个给定类型的变量,那么该类型的类型转换符就很容易得到了:
只需要把声明中的变量名和声明末尾的分号去掉,再将剩余的部分用一个括号整个”封装“起来即可。
例如,有如下声明:float (*h)( ); 表示h是一个指向返回值为浮点类型的函数的指针。
因此,( float (*)( ) ) 表示一个”指向返回值为浮点类型的函数的指针“的类型转换符。
3. 分析( *(void(*)())0 )( ) ,调用首地址为0位置的子例程
第一步:
假定变量 fp 是一个函数指针,那么如何调用 fp 所指向的函数呢?
(*fp)( );
因为 fp 是一个函数指针,那么 *fp 就是该指针所指向的函数,所以(*fp)( )就是调用该函数的方法。不建议简写为 fp( )。
第二步:
(*0)( ); 能不能这样写呢?不行,因为运算符必须要一个指针来做操作数。而且,这个指针还应该是一个函数指针,这样经运算符 * 作用后的结果才能作为函数调用。
因此,上式必须对 0 做类型转换,转换后的类型可以大致描述为:”指向返回值为void类型的函数的指针“。(因为子例程返回值为void)
如果 fp 是一个指向返回值为void类型的函数的指针,那么(*fp)( )的值为void,fp的声明如下:void (*fp)( );
因此,我们可以用下式来完成调用存储位置为0的子例程:
void (*fp)( ); //先声明一个”指向返回值为void类型的函数的指针“ (*fp)( ); //调用该函数指针
这里默认fp初始化为0,这种写法不提倡。且多声明了一个”哑“变量。
一旦知道如何声明一个变量,也就知道了如何对一个常数进行类型转换,将其转型为改变了的类型:( void (*)( ) ) 0 。
因此,可以用( void (*)( ) ) 0 来替换fp,从而得到:( *(void(*)())0 )( ) ; 。
末尾的分号使得表达式成为一个语句。
使用typedef能够使表述更清楚:
typedef void (*funcptr)( ); ( *(funcptr)0 )( );
4. 考虑signal函数
在包含signal函数的C编译器实现中,signal函数接受两个参数:一个是代表需要”被捕获“的特定signal的整数值;另一个是指向用户提供的函数的指针,该函数用于处理”捕获到“的特定signal,返回值类型为void。
一般情况下,程序员并不主动声明signal函数,而是直接使用系统头文件signal.h中的声明。那么,signal函数是责骂声明的呢?
首先考虑用户定义的信号处理函数
该函数可以定义如下:
1 void sigfunc( int n ) //参数n是一个代表特定信号的整数值 2 { 3 /*特定信号处理部分*/ 4 }
sigfunc函数的声明可以如下:void sigfunc( int );
现在假定我们需要一个指向sigfunc函数的指针变量,不妨命名为sfp。*sfp则代表了sigfunc函数,因此*sfp可以被调用。
又假定sig是一个整数,则(*sfp)(sig)的值为void类型,因此可如下声明sfp:
1 void (*sfp) ( int );
因为signal函数的返回值类型与sfp的返回类型一样,上式也就声明了signal函数,我们可以如下声明:
1 void (*signal ( something )) (int);
此处的something代表了signal函数的参数类型。上面声明可以这样理解:
1. 传递适当的参数以调用signal函数;
2. 对signal函数返回值(为函数指针类型)解处引用(dereference);
3. 然后传递一个整型参数调用引用解除后所得的函数;
4. 最后返回值为void类型。
因此,signal函数的返回值是一个指向返回值为void类型的函数的指针。
那么,signal函数的参数又如何呢?signal函数接受两个参数:一个整型的信号编号,以及一个指向用户定义的信号处理函数的指针(即此前定义的sfp)。
sfp的类型可以通过将上面的声明中的sfp去掉而得到,即void (*)(int)。此外,signal函数的返回值是一个指向调用前的用户定义信号处理函数的指针,这个指针类型和sfp指针类型一致。
因此,可以如下声明signal函数:
1 void ( *signal( int,void (*) ( int )) ) ( int );
signal( int,void (*) ( int )) 是一个指向返回值为void类型的函数的指针。
同样的,使用typedef可以简化上面的函数声明:
1 typedef void (*HANDLER) ( int ); 2 HANDLER signal( int, HANDLER );
原文地址:https://www.cnblogs.com/lightuup/p/10612021.html