<!-- /* Font Definitions */ @font-face {font-family:宋体; panose-1:2 1 6 0 3 1 1 1 1 1; mso-font-alt:SimSun; mso-font-charset:134; mso-generic-font-family:auto; mso-font-pitch:variable; mso-font-signature:3 135135232 16 0 262145 0;} @font-face {font-family:"Cambria Math"; panose-1:2 4 5 3 5 4 6 3 2 4; mso-font-charset:0; mso-generic-font-family:roman; mso-font-pitch:variable; mso-font-signature:-1610611985 1107304683 0 0 159 0;} @font-face {font-family:Calibri; panose-1:2 15 5 2 2 2 4 3 2 4; mso-font-charset:0; mso-generic-font-family:swiss; mso-font-pitch:variable; mso-font-signature:-1610611985 1073750139 0 0 159 0;} @font-face {font-family:"/@宋体"; panose-1:2 1 6 0 3 1 1 1 1 1; mso-font-charset:134; mso-generic-font-family:auto; mso-font-pitch:variable; mso-font-signature:3 135135232 16 0 262145 0;} /* Style Definitions */ p.MsoNormal, li.MsoNormal, div.MsoNormal {mso-style-unhide:no; mso-style-qformat:yes; mso-style-parent:""; margin:0cm; margin-bottom:.0001pt; text-align:justify; text-justify:inter-ideograph; line-height:150%; mso-pagination:none; font-size:10.5pt; mso-bidi-font-size:11.0pt; font-family:"Calibri","sans-serif"; mso-ascii-font-family:Calibri; mso-ascii-theme-font:minor-latin; mso-fareast-font-family:宋体; mso-fareast-theme-font:minor-fareast; mso-hansi-font-family:Calibri; mso-hansi-theme-font:minor-latin; mso-bidi-font-family:"Times New Roman"; mso-bidi-theme-font:minor-bidi; mso-font-kerning:1.0pt;} .MsoChpDefault {mso-style-type:export-only; mso-default-props:yes; mso-bidi-font-family:"Times New Roman"; mso-bidi-theme-font:minor-bidi;} .MsoPapDefault {mso-style-type:export-only; text-align:justify; text-justify:inter-ideograph; line-height:150%;} /* Page Definitions */ @page {mso-page-border-surround-header:no; mso-page-border-surround-footer:no;} @page Section1 {size:612.0pt 792.0pt; margin:72.0pt 90.0pt 72.0pt 90.0pt; mso-header-margin:36.0pt; mso-footer-margin:36.0pt; mso-paper-source:0;} div.Section1 {page:Section1;} -->
函数指针的典型应用
在 C 语中,最难学的个人认为是指针,但是,很多初学者对指针不是很了解,就算理解一点的人,通常会觉得指针在 C 中应用不太大,除了一般的参数传递、应用指针来进行对数组的访问、回调函数外,很少用到其它的地方。对指针掌握好一点的人也许会用函数指针数组与命令行参数来进行调用相关的操作,而不用 switch 语。下面是一个应用函数指针数组进行函数调用的例子,没有应用命令行参数来进行。
/*
* 这是一个简单的函数指针数组的练习。
* 主要使休码更加简洁。当然,对于指针不太了解的人来说
* 有一点难度。
*/
#ifndef TEST_C_
#define TEST_C_
#include <stdio.h>
int add(int,int);
int sub(int,int);
int mul(int,int);
int div(int,int);
int mod(int,int);
int main(void)
{
int a;
int b;
int c;
/* 声明函数指针数组 */
int (*oper_funel[])(int,int) = {add,sub,mul,div,mod};
while(1)
{
printf(" 这是一个简单的计算器,主要有下面的功能! /n");
printf(" 1: 加 /n 2: 减 /n 3: 乘 /n 4: 除 /n 5: 求模 /n");
printf(" 输入格式为 :num1 num2 操作 /n");
printf(" 请选择 :");
scanf("%d %d %d",&a,&b,&c);
printf("Result is:%d/n",oper_funel[c - 1](a,b));
}
return 0;
}
int add(int a,int b)
{
return a + b;
}
int sub(int a,int b)
{
return a - b;
}
int mul(int a, int b)
{
return a * b;
}
int div(int a, int b)
{
return a / b;
}
int mod(int a,int b)
{
return a % b;
}
#endif
在这个例子中应用一个函数指针数组来进行函数的调用,这样代码更加紧密,同时也更加可读,当然在效率上不一定比应用 switch 语句快。
其实指针的中的一个重要的内容是,函数指针是个人认为特别重要的一点,在 Linux 操作系统中,当我们写基于 Linux 操作系统时,需要进行屏蔽上层应用软件对硬件的直接操作,还要提供一组通用的接口给上层应用软件调用,这样就好像在上层应用软件中,直接进行读写操作就可以完成对不同的操作,然而提供的函数接口就只是一组,需要根据使用者的参数传递来进行区分对不驱动程序的调用。下面结构体是 Linux 内核中 fs.h 中的一个结构体,它是上层文件操作与底层驱动程序之间的一个桥梁。
struct file_operations {
struct module *owner;
loff_t (*llseek) (struct file *, loff_t, int);
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t (*aio_read) (struct kiocb *, char __user *, size_t, loff_t);
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
ssize_t (*aio_write) (struct kiocb *, const char __user *, size_t, loff_t);
int (*readdir) (struct file *, void *, filldir_t);
unsigned int (*poll) (struct file *, struct poll_table_struct *);
int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
int (*mmap) (struct file *, struct vm_area_struct *);
int (*open) (struct inode *, struct file *);
int (*flush) (struct file *);
int (*release) (struct inode *, struct file *);
int (*fsync) (struct file *, struct dentry *, int datasync);
int (*aio_fsync) (struct kiocb *, int datasync);
int (*fasync) (int, struct file *, int);
int (*lock) (struct file *, int, struct file_lock *);
ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *);
ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *);
ssize_t (*sendfile) (struct file *, loff_t *, size_t, read_actor_t, void *);
ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
int (*check_flags)(int);
int (*dir_notify)(struct file *filp, unsigned long arg);
int (*flock) (struct file *, int, struct file_lock *);
};
在进行驱动程序设计时,驱动程序开发人员只需写出相应的功能,再通过与 file_operations 相应的函数进行对应,当把驱动程序块加如内核或者通过手动加入后,就可以进行对相关硬件的操作台。以下定义几个文件操作最常用的三个功能函数。
Test_open(struct inode *inode,struct file *filp);
Test_read(struct_inode *inode,struct file *filp);
Test_write(int struct_file *filp,const char *buffer,size_t count,loff_t *f_pos);
在驱动程序设计时完成如下的映射。
Struct file_operation Test_fops = {
.owner = THIS_MODULE;
.open = Test_open;
.read = Test_read;
.write = Test_write;
};
这样,当驱动程序加载到内核后,就可以应用相关的函数进行操作而与我们平常的文件操作没有什么不同,其实 Linux 中把设备当着文件进行管理。在这里不进行相关的分析,因为这需要读者对 Linux 内核有一定的理解(本人也在模索中),所以,如果我亲爱的读者不能理解,那么可以这样理解,应用函数指针可以其实的功能远大于你现在所能理解的,而不是书上的那样的例子,写一个函数,再声明一个函数指针,再进行调用那么简单。
最后, void * ,这个指针也很有用,请不要把它与 void 相提并论,当应用到的时候就自然知道其用处所在了。
好了,说了这么多,也不知道说了些什么,如果有不对的地方,希望你 ---- 我亲爱的读者给予指出,让本人也有改正与学习的机会。