所谓函数指针就是一个指向函数的指针,也就是说我们定义一个函数指针量后,这个变量所在的空间要保存一个函数的地址。那么函数指针除了作为回调函数的传参之外还有什么作用呢?这里我们就结合staitc的作用来探讨一下函数指针是如何作为间谍的。
首先讨论一下static的作用,static从本质来讲就两个作用:
第一、 限定存储域:被static修饰的变量无论是局部变量还是全局变量都将被编译器存放在静态区。而实际上在gcc编译完生成的ELF格式文件中并没有静态区这个概念,所谓静态区是我们在概括讨论程序数据段的一种泛称。实际上编译器会根据具体情况把被static修饰的变量分为两类:当变量被定义并初始化为非零值的时候,变量将放在.data段;当否则为初始化或初始化为零的时候将放在.bss段。我们在不深入讨论的时候暂且可以将此两段概括为静态区。而放在静态区的变量由于存储域的原因导致生命周期很长,长度为程序(确切讲应该是该程序运行后的进程)的一次运行过程,而普通局部变量由于在运行过程中被系统分配在栈区所以生命周期只是一次函数的调用过程。
第二、 限定作用域:由于静态还是普通局部变量本身的作用域就是函数内部,因此static的作用域主要是对全局变量和函数的限定。被staitc修饰的全局变量或函数都被编译器标记为仅在本文件中使用,由于编译器在编译过程中是以.c结尾的源文件为单位依次生成以.o结尾的目标文件,所以最后连接器在连接过程中将不允许被static修饰的变量或函数的地址对外链接。这样既可以防止全局变量或函数的重名问题,又可以防止由于无关的全局变量误操作引起的程序逻辑问题。因此static就限定了变量或函数的作用域。
那么被static修饰的函数就真的只能在本文件中使用了吗?答案是否定的,由于C语言的精华——指针的强大功能让我们很轻松的利用函数指针就可以实现在文件外部调用被static修饰的函数。
首先来看一段实验代码(详见图1):
图1
代码中编写了两个源文件分别为main.c和global_fun.c。
其中main.c中定义了一个被static修饰的函数int local_fun(void);
global_fun.c中定义了global_fun()函数;
两个函数都只打印了一句话说明自己是哪个函数。由于static的限定作用导致global_fun中想要调用local_fun函数是不可能的,编译器会在连接期间报错(详见图2):
图2
接着修改程序,将global_fun函数定义为带有一个参数为函数指针的函数,并且在main函数中定义一个函数指针p指向被static修饰的静态函数local_fun,接着调用global_fun函数并给其传递参数p(详见图3):
图3
这时候编译运行,一切正常(详见图4):
图4
总结:指针是C语言的精华所在,指针的灵活实用将使你的开发工作变得游刃有余事半功倍。因此熟练掌握指针的操作对于一位从事C开发的程序员来说是不可或缺的基本功。而正因为指针的灵活多变导致我们在使用指针操作数据的时候要格外谨慎,一不小心将会导致致命的程序错误。但是C语言再强大终究只是一门工具,只要理解操作系统的原理熟悉C语言的规则然后严密谨慎地使用这门工具,那么你将会越发感受到C编程的乐趣。
原文链接: