将0转型为指向返回值为void的函数的指针 void x0.docx
- 文档编号:30572591
- 上传时间:2023-08-16
- 格式:DOCX
- 页数:19
- 大小:23.17KB
将0转型为指向返回值为void的函数的指针 void x0.docx
《将0转型为指向返回值为void的函数的指针 void x0.docx》由会员分享,可在线阅读,更多相关《将0转型为指向返回值为void的函数的指针 void x0.docx(19页珍藏版)》请在冰豆网上搜索。
将0转型为指向返回值为void的函数的指针voidx0
(void(*)())0的含义
(void(*)())0的含义:
1. fp是一个指针{有*},她指向返回值为void{有(void)}类型的函数{有()}:
void(*fp)();调用方式简写为:
(*fp)();
2. 制作其对应的类型强制转换符:
void(*)()
3. 存储位置为0的强制转换为一个指向返回值为void类型的函数的指针:
(void(*)())0
4. 用上式代替fp,从而实现调用存储位置为0的子例程:
(*(void(*)())0)();
5. 利用typedef简化:
typedefvoid(*funcptr)();(*(funcptr)0)();
(void(*)())0的含义:
实际上就是将地址0强制转换为一个指向返回值为void类型的函数的指针。
下面将相关基础知识进行介绍,其中参考了网上一些文章,名单不再列出,谢谢各位大虾的贡献:
1、c语言的声明
2、类型转换符的制作
3、signal函数分析
4、typedef用法
5、const用法
6、typedef的好处
1 C语言的声明
声明由两部分组成:
类型以及声明符:
floatf,g;
float((f));//对其求值时,((f))的类型为浮点型,可以推知,f也是浮点型
float*g(),(*h)();//g是函数,该函数的返回类型为指向浮点数的指针
//h是个指针,且是一个函数指针,该指针指向函数返回值,该返回值是一个float型
(*fp)()简写为fp()//函数调用方式,其中fp为函数指针
*((*fp)())简写为*fp()//函数返回值为某个类型的指针
、2 类型转换符制作
类型转换符制作:
1、去掉声明中的变量名、分号;
2、将剩余部分用括号"封装"起来
float(*h)();-->(float(*)())//指向返回值为float型的函数指针的类型转换符
(*0)();//返回值为void类型的函数指针
如果fp是一个指向返回值为void类型的函数的指针,那么(*fp)()的值为void,fp的声明如下:
void(*fp)();
因此可以用下式完成调用存储位置为0的子例程:
void(*fp)();(*fp)();
这种写法的代价是多声明了一个哑变量,我们常将0转型为“指向返回值为void的函数的指针”:
(void(*)())0
用上式代替fp,从而得到:
(*(void(*)())0)();
typedefvoid(*funcptr)();
将0转型为“指向返回值为void的函数的指针”-----(void(*)())0
(*(funcptr)0)();
3 signal函数
signal函数接受两个参数:
信号类型的整型值、指向用户提供的信号处理函数指针
用户提供的信号处理函数返回值类型为:
void
signal的返回值类型:
指向调用前的用户定义信号处理函数的指针
下面分析signal函数在signal.h中是如何声明的
1. 用户定义信号处理函数:
voidsigfunc(intn){/*特定信号处理部分*/}
2. sigfunc声明:
voidsigfunc(int);
3. 假设sfp指向sigfunc函数,sigfunc函数声明:
void(*sfp)(int);
4. 假设sig为一整数,则(*sfp)(sig)返回值为void类型
5. sfp与signal返回值类型相同,故声明signal函数:
void(*signal(something))(int);
//something为signal的参数类型
//过程分析:
传递一个适当的参数调用signal;对signal的返回值解引用;传递一个参数调用解引用后
(void(*)())0
将0转型为“指向返回值为void的函数的指针”-----(void(*)())0
//得到的函数;得到返回值为void型
//signal函数返回值是一个指向返回值为void类型的函数的指针
6. signal其中参数为:
int、void(*)(int),故signal函数:
void(*signal(int,void(*)(int)))(int);
7. 用typedef简化:
typedefvoid(*HANDLER)(int);HANDERsignal(int,HANDER);
将0转型为“指向返回值为void的函数的指针”-----(void(*)())0
4 typedef用法
例1:
int*(*a[5])(int,char*);
typedefint*(*PF)(int,char*);//PF是一个类型别名
PFa[5];//跟int*(*a[5])(int,char*);的效果一样!
//很多初学者只知道typedefchar*pchar;但是对于typedef的其它用法不太了解。
//StephenBlaha对typedef用法做过一个总结:
“建立一个类型别名的方法很简单,
//在传统的变量声明表达式里用类型名替代变量名,然后把关键字typedef加在该语句的开头”。
例2:
void(*b[10])(void(*)());
typedefvoid(*pfv)();
typedefvoid(*pf_taking_pfv)(pfv);
pf_taking_pfvb[10];//跟void(*b[10])(void(*)());的效果一样!
例3:
double(*)()(*pa)[9];
typedefdouble(*PF)();const和volatile在类型声明中的位置。
5 const用法(volatile是一样的)
volatile修饰的量就是很容易变化,不稳定的量,它可能被其它线程,操作系统,硬件等等在未知的时间改变,所以它被存储在内存中,每次取用它的时候都只能在内存中去读取,它不能被编译器优化放在内部寄存器中。
constint;//int是const
constchar*;//char是const
char*const;//*(指针)是const
constchar*const;//char和*都是const
另外一个对等的写法(const在后面):
intconst;//int是const
charconst*;//char是const
char*const;//*(指针)是const
charconst*const;//char和*都是const
const在后面有两个好处:
A.const所修饰的类型正好是在它前面的那一个
B.用到typedef的类型别名定义时,如typedefchar*pchar,当const在前面的时候,就是constpchar,它的真实含义是char*const,而不是constchar*。
将0转型为“指向返回值为void的函数的指针”-----(void(*)())0
6 typedef的好处
使用typedef来编写更美观和可读的代码。
所谓美观,意指typedef能隐藏笨拙的语法构造以及平台相关的数据类型,从而增强可移植性和以及未来的可维护性,使代码更健壮。
typedef使用最多的地方是创建易于记忆的类型名,用它来归档程序员的意图。
类型出现在所声明的变量名字中,位于typedef关键字右边:
typedefintsize;
注意typedef并不创建新的类型,仅仅为现有类型添加一个同义字,使用size:
voidmeasure(size*psz);
sizearray[4];
typedef可以掩饰复合类型,如指针和数组:
charline[81];chartext[81];
定义一个typedef,每当要用到相同类型和大小的数组时,可以这样:
typedefcharLine[81];
Linetext,secondline;
getline(text);
同样,可以象下面这样隐藏指针语法:
typedefchar*pstr;
intmystrcmp(pstr,pstr);
第一个typedef陷阱:
标准函数strcmp()有两个constchar*类型的参数。
因此,它可能会误导人们象下面这样声明:
intmystrcmp(constpstr,constpstr);
constpstr被编译器解释为char*const(一个指向char的常量指针),而不是constchar*(指向常量char的指针)。
这个问题很容易解决:
typedefconstchar*cpstr;
intmystrcmp(cpstr,cpstr);
typedef行为有点像#define宏,用其实际类型替代同义字。
不同点是typedef在编译时被解释,因此让编译器来应付超越预处理器能力的文本替换。
例如:
typedefint(*PF)(constchar*,constchar*);
这个声明引入了PF类型作为函数指针的同义字,该函数有两个constchar*类型的参数以及一个int类型的返回值。
如果要使用下列形式的函数声明,那么上述这个typedef是不可或缺的:
PFRegister(PFpf);
Register()的参数是一个PF类型的回调函数,返回某个函数的地址,其署名与先前注册的名字相同,如果不用typedef,如何实现这个声明的:
int(*Register(int(*pf)(constchar*,constchar*)))(constchar*,constchar*);
typedef就像auto,extern,mutable,static,和register一样,是一个存储类关键字。
这并不是说typedef会真正影响对象的存储特性;它只是说在语句构成上,typedef声明看起来象static,extern等类型的变量声明。
第二个陷阱:
typedefregisterintFAST_COUNTER;//错误编译通不过
不能在声明中有多个存储类关键字,因为符号typedef已经占据了存储类关键字的位置。
在typedef声明中不能用register(或任何其它存储类关键字)。
typedef定义机器无关的类型:
例如定义一个叫REAL的浮点类型,在目标机器上它可以获得最高的精度:
typedeflongdoubleREAL;
typedefdoubleREAL;//不支持longdouble的机器上
typedeffloatREAL;//不支持double的机器上
不用修改源代码,便可在每一种平台上编译这个使用REAL类型的应用程序。
唯一要改的是typedef本身。
标准库的平台无关类型:
size_t,ptrdiff和fpos_t就是很好的例子.
C语言指针
1、指针函数:
表示的是函数的返回值为指针
int *max(int,int);
2、函数的指针、函数指针:
表示定义一个指针,用来存储函数的指针,或者说函数的首地址
定义:
函数返回值类型 (*P)(函数形参列表);
3、数组的指针、数组的指针
一维数组的指针:
int*p;
多维数组的指针:
int*p[]; 还是指向数组的指针.
这里的应用最常见的是main函数的定义。
4、指针数组:
表示的是这是一个数组,但是数组的元素是指针
定义:
int (*p)[];
复杂的函数指针说明
以下所说的结合顺序就是由内向外一层一层剥,有助于理解。
1.intfunc(int);//定义一个函数,该函数返回值int,接受一个int型参数;结合顺序为:
func(int)--intfunc(int)
2.int*return_pointer_array_func1(int)[10];return_pointer_array_func1返回指针数组的函数,
//结合顺序为:
return_pointer_array_func1(int)--return_pointer_array_func1(int)[10]--*return_pointer_array_func1(int)[10]--int*return_pointer_array_func1(int)[10]
3.intreturn_array_func1(int)[10];定义一个函数return_array_func1,该函数返回值int[10],接受一个int型参数;
//结合顺序为return_array_func1(int)--return_array_func1(int)[10]--intreturn_array_func1(int)[10]
//4~5两者之间差别是,前者是拥有10个整型指针为元素的数组,array1是一个数组名.(存放指针的数组)
// 后者是pointer1是一个指针,该指针指向拥有10个整型变量为元素的数组.(指向数组的指针)
4.int*array1[10];//结合顺序为array1[10]--*array1[10]--int*array1[10]
5.int(*pointer1)[10];//结合顺序为*pointer1--(*pointer)[10]--int(*pointer)[10]
//pointer1=array1;是错误的两者类型不相同.
6.int(*return_array_pointer_func(int))[10];//定义一个返回数组指针的函数return_array_pointer_func.结合顺序为:
//return_array_pointer_func(int)--*return_array_pointer_func(int)--(*return_array_pointer_func(int))[10]
//--int(*return_array_pointer_func(int))[10]
7.int(*func_pointer_array[10])(int);//定义一个返回int,接受一个int参数的函数指针数组.结合顺序为:
//func_pointer_array[10]--(*func_pointer_array[10])--(*func_pointer_array[10])(int)--int(*func_pointer_array[10])(int)
8.int(*(*func_pointer_pointer_array)(int))[10];//定义一个函数指针的指针的数组.结合顺序为:
//*func_pointer_pointer_array--(*func_pointer_pointer_array)(int)--(*(*func_pointer_pointer_array)(int))
//--(*(*func_pointer_pointer_array)(int))[10]--int(*(*func_pointer_pointer_array)(int))[10]
9.int*(*(*fun_pointer_pointer_array_pointer)(int))[10];//定义一个函数指针的指针数组的指针.结合顺序为:
//*fun_pointer_pointer_array_pointer--*fun_pointer_pointer_array_pointer)(int)--(*(*fun_pointer_pointer_array_pointer)(int))
//--(*(*fun_pointer_pointer_array_pointer)(int))[10]--*(*(*fun_pointer_pointer_array_pointer)(int))[10]
//--int*(*(*fun_pointer_pointer_array_pointer)(int))[10]
10.float(*(*getvalue())[])(); ////定义一个函数,该函数不接受参数,返回值类型是一个指针,返回值类型是一个指针数组
//返回值类型是一个指针数组指针,返回值类型是一个指针数组函数指针,该函数有一个float返回值,不接受参数结合顺序为:
//getvalue()--(*getvalue())--(*getvalue())[]--(*(*getvalue())[])--(*(*getvalue())[])()
//--float(*(*getvalue())[])();
//定义一个函数,该函数不接受参数,返回值类型是一个指针,返回值类型是一个指针数组,返回值类型是一个指针数组指针,返回值类型是一个指针数组函数指针,该函数有一个float返回值,不接受参数
11.void*(*func_pointer1)(char,int(*)());//定义一个函数指针,结合顺序为:
//*func_pointer1--(*func_pointer1)(char,int(*)())--void*(*func_pointer1)(char,int(*)());
12.void**(*func_pointer2)(int&,char**(*)(char*,char**)); //定义一个指针,该指针是一个函数指针,该函数接受两个参数,
//一个参数是int&型,一个是char**(*)(char*,char**)型,返回值是void**型.结合顺序为:
//*func_pointer2--(*func_pointer2)(int&,char**(*)(char*,char**))--
//**(*func_pointer2)(int&,char**(*)(char*,char**))--void**(*func_pointer2)(int&,char**(*)(char*,char**));
13.float(*(*func_array_pointer1[10])(int&))[5];//定义一个数组,该数组存放指针,该数组存放函数指针,
//函数的返回值是指向数组的指针,参数是int&.结合顺序为:
//func_array_pointer1[10]--*func_array_pointer1[10]--(*func_array_pointer1[10])(int&)--
//(*(*func_array_pointer1[10])(int&))--(*(*func_array_pointer1[10])(int&))[5]
//--float(*(*func_array_pointer1[10])(int&))[5]
复杂的函数指针例子分析
一个最简单的函数指针定义如下:
Void(*funcPtr)();//funcptr是一个函数指针,它指向的函数没有参数,返回值为void
非常复杂的函数指针定义:
1.Void*(*(*fp1)(int))[10];
解析:
Void*X[10];è这是一个有10个void*类型的元素的数组。
X=*(*fp1)(int),从而可以看出(*fp1)(int)它是一个指针,指向一个数组。
这个数组有10个void指针类型的元素。
Fp1是一个函数指针,它的参数是一个int型的参数。
返回值为一个指向含有10个void*元素的数组的指针。
2.Void*(*fp1)(int)[10];
解析:
void*X[10];èX是一个有着10个void*类型的数组
X=(*fp1)(int);
Fp1是一个函数指针,它有一个整型参数,其返回值是一个有着10个void*类型的元素的数组。
3.Void(*fp1)(int)[10];
解析:
voidX[10]èX是一个有着10个void类型的数组
X=(*fp1)(int);
Fp1是一个函数指针,它有一个整型参数,其返回值是一个有着10个void类型的元素的数组
若是这个形式,Void(*fp1)(int)[10],则其返回值为一个有10个void类型的数组。
4.Float(*(*fp2)(int,int,float))(int);
解析:
FloatX(int)èX是一个函数,有一个整型参数,返回值是一个浮点数。
X=*(*fp2)(int,int,float);
Fp2是一个函数指针,它有三个参数,前两个是整型,最后一个是浮点型。
其返回值是一个指针,是一个指向函数的指针(函数指针)。
这个函数指针所指向的函数的原型是只有一个整型参数,返回值是一个浮点数。
5.Typedefdouble(*(*(*fp3)())[10])();
解析:
fp3是一个函数指针;它不带参数;返回值是一个指针。
X=(*(*fp3)())
Typedefdouble(*X[10])()
X是一个数组,他有10个元素,它的元素都是函数指针,这个函数指针所指向的函数原型是一个没有参数,返回值为double类型的函数。
综合起来就是:
fp3是一个新定义的数据类型,它是一个函数指针,这个函数指针所指向的函数原型是不带参数,返回值是一个指向数组的指针。
这个数组有10个元素,其元素类型是一个函数指针,这个函数指针所指向的函数原型是一个没有参数,返回值为double类型的函数。
6. Int(*(*fp4())[10])();
解析:
fp4是一个函数,他没有参数,返回值是一个指针;
X=(*fp4());
Int(*X[10])();
X是一个数组,其有10个元素,每个元素都是一个函数指针,这个函数指针所代表的函数原型是一个没有参数,返回值是整型的函数。
综合起来就是:
fp4是一个函数,他没有参数,返回值时一个指向数据的指针,这个数组有10个元素,每个元素都是一个函数指针,这个函数指针所代表的函数圆型是一个没有参数,返回值是整型的函数。
typedef
一、typedef结构的问题
当用下面的代码定义一个结构时,编译器报了一个错误,为什么呢?
莫非C语言不允许在结构中包含指向它自己的指针吗?
请你先猜想一下,然后看下文说明:
typedefstructtagNode
{
char*pItem;
pNodepNext;
}*pNode;
答案与分析:
1、typedef的最简单使用
typedeflongbyte_4;
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 将0转型为指向返回值为void的函数的指针 void x0 转型 指向 返回 函数 指针