** 3. 程序运行的实质就是将程序分成可执行部分和数据部分,通过可执行部分对数据进行加工计算得到目标数据;**
注意: typedef修饰后定义的是类型, p1 pfunc;是定义p1函数指针类型的变量pfunc,pfunc = func1; 是给pfunc变量赋值; 未用typedef修饰定义的是变量, p1 = func1;是给p1变量赋值
概述 (1)递归函数就是在函数内部又调用了本身的函数。 (2)递归有区别于循环,递归是一层层深入调用,然后逐层返回结果,而循环是循环调用后直接返回结果; (3)函数调用时,局部变量、实参和返回值都会保存在栈中,每次调用都会占用空间,因此使用递归函数时注意栈内存的消耗,递归调用必须有一个终止递归的条件,否则会陷入死循环递归,最终也会栈溢出;
int func(int n) { printf("%d\n", n); //递归调用4次,打印结果为4 3 2 1 if (n > 1) { func(n-1); //递归调用 } printf("n = %d\n", n); //返回4次的值,结果为1,2,3,4; } int main() { func(4); }静态链接库 (1)静态链接库的函数库源码,是将编译后形成众多的.o二进制文件归档成.a文件,然后将.a库文件与.h头文件发布 (2)用户根据.h头文件得到每个函数的原型,以便在自己的.c文件中传参调用,然后链接时链接器会直接到.a函数库中,使用静态链接库在链接时需要加-static来指定静态链接,将被调用函数的.o二进制代码链接进可执行文件; (3)由于使用静态库时,会将函数库中的函数链接进文件中,这就导致了当多个程序都含有共同的一个函数时,就会每个程序都链接这个函数,从而占用大量的内存降低效率;
自己制作静态链接库 (1)编写函数库func.c文件,然后只编译不链接,生成.o文件:gcc -c func.c -o func.o,并在func.h中声明func.c中的函数; (2)通过ar命令将.o文件归档成.a文件:ar -rc func.o -o libfunc.a (3)在使用时调用库函数及头文件 (4)编译时,通过-lfunc链接libfunc.c函数库,通过-L.指定在当前目录下查找函数库:gcc -c test.c test -lfunc -L. (5)可以通过nm libfunc.a来确定libfunc.a中的.o文件,每个.o文件有多少个func函数。
#inlcude "func.h" //调用库函数的头文件 int main(void) { func1(); //调用库函数中的函数 func2(4, 5); return 0; }动态链接库 (1)当使用动态链接库时,要注意-L指定动态库的地址,动态库文件不会被链接进可执行程序中,而是只是做一个标记。 (2)当程序执行当中若需要调用库函数时,会到动态库中加载这个函数到内存中,当其他程序也需要该库函数时,就直接跳转到第一次加载的地方去执行,无需重复加载; 注意: (1)使用函数库,需要包含相应的头文件; (2)有些库函数链接时需要额外用-lxxx来指定链接;
自己制作动态链接库 (1)过程同静态库一样,区别在于在编译库文件是需要加上-fPIC,fPIC是指定库函数为位置无关码,因为任何位置都有可能调用库函数,所以需要指定库函数为位置无关; (2)使用gcc编译成.so文件,加-shared后缀成共享类型:
gcc -c func.c -o func.o -fPIC; gcc -o libfunc.so func.o -shared;(3)调用库函数后,编译主函数的方式与调用静态库方式相同,在同目录下静态库与动态库同名时,系统默认先链接动态库;
gcc -o test test.c -lfunc -L.(4)由于调用动态库时,只是做了调用动态库函数的标记,因此在运行时系统会先LD_LIBRARY_PATH这个环境变量指定的目录去找动态库函数,若未找到再到默认/usr/lib目录下调用库函数,而自己制作的动态库在当前目录下,因此需要将libfunc.so导入到环境变量中:
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/book/test1(5)将目录导入环境变量后就可以执行test文件。注意:编译时加 -lfunc -L是链接时为了标记出调用出动态库函数;而运行时无法运行需要修改变量,是由于系统运行时到指定和默认的目录下寻找动态库; (5)ldd命令可以得到文件中调用了多少库函数及是否调用成功;
/******调用成功*******/ book@www.100ask.org:~/test1$ ldd test linux-vdso.so.1 => (0x00007fff5bbed000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f5614a6e000) /lib64/ld-linux-x86-64.so.2 (0x00007f5614e38000) /**********调用失败*********/ linux-vdso.so.1 => (0x00007ffd7a9f9000) libfunc.so => not found libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f0ccdbf5000) /lib64/ld-linux-x86-64.so.2 (0x00007f0ccdfbf000) 数学库函数 (1)math.h:/usr/include/x86_64-linux-gnu/bits$,需要数学函数(如开平方、三角函数等)的时候,需要包含数库库; (2)注意区分编译错误与链接错误 math.c:9:13: warning: incompatible implicit declaration of built-in function ‘sqrt’ [enabled by default] //编译错误:math.c:9:13:逐行编译发现错误 math.c:(.text+0x1b): undefined reference to `sqrt' collect2: error: ld returned 1 exit status //链接错误:ld:连接器(3)上述链接错误:sqrt函数有声明(mathcalls.h)、有引用(math.c),但找不到没有函数体,即无法链接到函数库;原因是C语言默认链接常用的库,若要链接不常用的库,需要链接时用-lxxx来指示链接器去到libxxx.so函数库中去查找这个函数。通过ldd a.out即ldd命令来查看文件中用到的那些库函数;