深入浅出C语言(5)----函数

函数可以分为普通函数和函数指针所指向的函数两种,本质上没有多大的区别。函数名都是地址。
示例1:
void test();
void main()
{
 int addr = (int)test; //这里可以获得函数的地址值
 test(); //调用
}

void test()
{
}
编译器编译的时候,已经把各个函数名转化地址值了。所以也就能采取 int addr = (int)test; 来获取了。 main函数中的test(); 的调用,本质上也是汇编指令跳
到 test地址处去执行代码。 不过,指令跳转的地址是一个相对main函数地址值的地址,所以不一定等到(int)test;地址值。由于采用了相对地址,所以整个代码执行的地址可以改动的。
理论上,对于内存所有的代码,如果知道其函数的地址,都是可以直接跳到该处执行的。只不过在现代的操作系统中,做了内存保护,一般情况下不充许这样做。在
windows平台下,Microsoft也只是开一个接口:远程线程调用。 就是充许当前程序直接进入目标进程中读取内存中所有的数据,并函数调用的。

在目前我们所写的简单示例程序中,我们都没有调用任何库函数的。
在理论上,编译器所支持的C语言数据类型与函数已经能让我们实现任何功能了。比如,我们可以自己根据标准C库函数的说明,去实现自己的库。
标准库是怎么实现的呢?? 大家可以参考一下P.J.Plauger 写的<The Standard C Library>, 中文翻译《C标准库》。此书把平时我们所用的标准库函数的实现过程
都写得很清楚,大家可以参考一下里面的优秀写法。比如,printf(const char *s,…) 中的不定参数的实现方法与原理。标准库中所涉及到的IO操作有一些是与操作系统的driver有关的。比如文件读写之类,这些可以忽略不考虑。

在现代的C编译器中,各种编译器所实现标准库接口是一致的,实现方法可能有差别,但这不妨碍我们编程使用。一般实现了库函数后,会封装在一起,比如封成lib库文件的形式供程序调用。前面也讲过,调用任何函数,编译器都要先看到声明或定义,所以lib库需要配上一系列声明库函数的头文件。 头文件 + lib库 这才构成编译器对完整库的使用的。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章