一、C语言由源代码生成可执行程序的过程如下
C源程序->预处理->编译->优化程序->汇编程序->链接程序->可执行文件
- 预处理过程:
读入源代码,检查包含预处理指令的语句和宏定义,并对源代码进行转换。预处理过程还会删除程序中的注释和多余的空白字符。
在C语言的程序中包括各种以符号#开头的编译指令,这些指令称为预处理命令。预处理命令属于C语言编译器,而不是C语言的组成部分,通过预处理命令可扩展C语言程序设计的环境。
预处理指令是以#号开头的代码行,#号必须是该行除了任何空白字符外的第一个字符。
#后是指令关键字,在关键字和#号之间允许存在任意个数的空白字符,整行语句构成了一条预处理指令,该指令将在编译器进行编译之前对源代码做某些转换。
预处理指令主要有以下三种:
1)包含文件:将源文件中以#include格式包含的文件复制到编译的源文件中,可以是头文件,也可以是其它的程序文件。
2)宏定义指令:#define指令定义一个宏,#undef指令删除一个宏定义。
3)条件编译:根据#ifdef和#ifndef后面的条件决定需要编译的代码。
- 编译:
扫描源代码,对其进行初步的转换,产生新的源代码提供给编译器。
二、静态库和动态库
//book265.cpp中有#include "public.h",而public.h的实现在public.cpp,编译
//book265时就用下面命令将public.cpp的方法引用进来
g++ -o book265 book265.cpp public.cpp
//上面命令和下面是等价的,因为始终只有一个main函数
g++ book265.cpp public.cpp -o book265
公用函数库的程序文件public.cpp程序文件是源代码,对任何程序员是可见的,没有安全性可言,但是,在实际开发中,出于技术保密或其它方面考虑,开发者并不希望提供公用函数库的源代码。
C/C++提供了一个可以保证代码安全性的方法,把公共的程序文件编译成库文件,库文件是一种可执行代码的二进制形式,可以与其它的源程序一起编译,也可以被操作系统载入内存执行。
库文件分为静态库与动态库。
区别:
静态库源代码修改后,静态库需要重新编译,程序也要重新编译。
动态库源代码修改后,只需要编译动态库文件即可,程序不需要重新编译。
如果在动态库文件和静态库文件同时存在,优先使用动态库编译。
**1. 静态库
命名方式:**
静态库文件名的命名方式是“libxxx.a”,库名前加”lib”,后缀用”.a”,“xxx”为静态库名。
把程序文件public.cpp编译成静态库的指令:
//libpublic.a是静态库名,public.cpp是源文件
g++ -c -o libpublic.a public.cpp
使用静态库:
- 方法一:
直接把调用者源代码和静态库文件名一起编译。
g++ -o book265 book265.cpp libpublic.a
- 方法二:
采用L参数指定静态库文件的目录,-l参数指定静态库名。
g++ -o book265 book265.cpp -L/home/wucz/demo -lpublic
注意:
1)如果要指定多个静态库文件的目录,用法是“-L/目录1 -L目录2 -L目录3”;2)链接库的文件名是libpublic.a,但链接库名是”public”,不是“libpublic.a”;3)如果要指定多个静态库,用法是“-l库名1 -l库名2 -l库名3”。
2. 动态库
动态库在编译时并不会被连接到目标代码中,而是在程序运行时才被载入,因此在程序运行时还需要指定动态库的目录。
命名方式:
与静态库类似,前缀相同,为“lib”,后缀变为“.so” “xxx”为动态库名。
把程序文件public.cpp编译成动态库的指令:
g++ -fPIC -shared -o libpublic.so public.cpp
如果在动态库文件和静态库文件同时存在,优先使用动态库编译。
使用动态库的方法与使用静态库的方法相同:
g++ -o book265 book265.cpp -L/home/wucz/demo -lpublic
报错:
执行程序book265时,出现以下提示:
这是因为采用了动态链接库的可执行程序在运行时需要指定动态库文件的目录,Linux系统中采用LD_LIBRARY_PATH环境变量指定动态库文件的目录。
采用以下命令设置LD_LIBRARY_PATH环境变量:
export LD_LIBRARY_PATH=/home/wucz/demo:.
注意:
1)如果要指定多个动态库文件的目录,用法是“export LD_LIBRARY_PATH=目录1:目录2:目录3:.”,目录之间用半角的冒号分隔,最后的圆点指当前目录。
动态库在编译的时候只做语法检查, 并没有被编译进目标代码,当程序执行到动态库中的函数时才调用该函数库里的代码。
动态函数库并没有整合进程序,所以程序的运行环境必须提供动态库路径。优点是,如果所使用的动态库发生更新改变,程序不需要重新编译,所以动态库升级比较方便。