Bootstrap

C语言之编译与库

预编译

C语言编译的4个阶段:预编译,编译,汇编,链接

预处理阶段会在源代码中查找预编译指令,其中主要是头文件展开(include),宏替换(define),选择性编译(ifdef)三种指令

预处理命令以符号#开头

优点:

        1,扩展了C程序设计的环境

        2,简化程序开发过程

        3,提高程序的可读性

注意;

        1,实际上不是C语言的一部分

        2,预编译指令在编译前由预处理程序对源文件的预处理文件进行加工

include

作用:

        引入头文件

        在预编译阶段,“#include” 指令会将该行代码替换为所引入的头文件中的实际代码内容

语法:

        1,#include <要引入的头文件名>

        用尖括号包含头文件,在系统指定的路径下找头文件

        2,#include "要引入的头文件名"

        用双引号包含头文件,先在当前目录下找头文件,找不到,再到系统指定的路径下找

注意:

        1,include经常用来包含头文件,也可以包含源文件,也可以在头文件中定义函数,但是不建议包含源文件和定义函数

        2,预处理只是对include等预处理操作进行处理并不会进行语法检查,编译阶段才会检查语法是否有误

define:宏

分类:

        不带参宏

        带参宏

不带参宏

步骤:

        1,宏定义

                静态定义

                        #define 宏名称 值

                        注意:值可有可无

                动态定义

                        在代码编译时加

                                -D 宏名=值        或        -D 宏名

        2,使用宏

                宏名称

        3,取消宏

                #undef 宏名称

                注意:

                        一旦取消宏,该宏名不能再使用

使用范围:

        宏定义开始到取消宏

带参宏

步骤:

        1,宏定义

                #define 宏名称(形参列表) 代码;

        2,使用宏

                宏名称(实参列表);

        3,取消宏

                #undef 宏名称

带参宏与带参函数的区别

        带参宏被调用多少次就会展开多少次,执行代码时没有函数调用的过程,不需要压栈弹栈,所以带参宏是浪费了空间,因为被展开多次,节省时间

        带参函数,代码只有一份,存在代码段,调用的时候去代码段取指令,调用的时候要压栈弹栈,有调用过程,带参函数是浪费了时间,节省了空间

选择性编译

作用:

        选择性地对代码进行编译

语法:

        判断存在

                #ifdef XXX

                语句1;

                #else

                语句2;

                #endif

                如果定义了宏XXX编译语句1,否则编译语句2

        判断不存在

                #ifndef XXX

                语句1;

                #else

                语句2;

                #endif

                如果没定义宏XXX编译语句1,否则编译语句2

        判断是否成立

                #if XXX

                语句1;

                #else

                语句2;

                #endif

                如果XXX为真编译语句1,否则编译语句2

头文件模版

#ifndef 自定义宏

#define 自定义宏

引入头文件

声明变量

声明函数

#endif

注意:此时需要在该头文件对应的源文件中引入这个头文件。另外,在使用该源文件中函数的其他源文件中也需要引入这个头文件,这样做可以避免重复声明的问题。

动态库与静态库

程序编译

分类:

静态编译:       gcc -static 源文件名 -o 生成的可执行文件名

动态编译:       gcc 源文件名 -o 生成的可执行文件名

静态编译与动态编译的区别

静态编译使用静态库,生成的可执行程序大,对库依赖小

动态编译使用动态库,生成的可执行程序小,对库依赖大

静态库:

        链接阶段,不管使用静态库中几个函数,都是加载整个静态句

动态库:

        第一步:在链接阶段,只是建立和所需要函数的关系

        第二步:在运行阶段,才将所需要的函数拷贝到可执行文件中

动态库

制作:

        gcc -shared 源文件名 -o lib动态库名.so

注意:

        如果制作动态时出现以下问题,需给制作动态库的命令加-fPIC      

使用:

        使用动态库的源文件与动态库在同一文件下

        gcc 源文件名 lib动态库名.so -o 可执行文件名

        注意:

                如果在执行可执行程序时出现一下问题需要加入

                export LD_LIBRARY_PATH=./:$LD_LIBRARY_PATH  

        使用动态库的源文件与动态库不在同一文件夹下

        gcc 源文件名 -o 生成的可执行文件名 -L库文件路径 -l库名 -I头文件所在路径

        注意:

                -L 是指定库文件的路径

                -l 指定找哪个库,指定的只要库文件名 lib 后面 .so 前面的部分
                -I 指定头文件的路径
        如果出现以下问题, 需要加入
        export LD_LIBRARY_PATH=库文件所在路径 :$LD_LIBRARY_PATH
        动态库文件在系统提供的文件夹
                系统提供的文件夹
                        /usr/lib        系统提供存储动态库的文件夹
                        /usr/include        系统提供存储头文件的文件夹
                gcc 源文件名 -l 库文件名 -o 生成的可执行文件夹

静态库

制作:

        首先,把将要编译成库文件的源文件编译为二进制文件。使用如下命令:
        gcc -c 源文件名 -o 二进制文件名.o

        接着,将生成的二进制文件转换为静态库文件,相应的命令是:

        ar rc lib库文件名.a 二进制文件名.o

使用:

    使用静态库的源文件与动态库在同一文件夹下    

     gcc -static 源文件名 lib动态库名.a -o 可执行文件名 

    使用静态库的源文件与动态库不在同一文件夹下

                  gcc -static 源文件名 -o 生成的可执行文件名 -L库文件路径 -l库名 -I头文件所 在路径

            静态库文件在系统提供的文件夹

                   /usr/lib 系统提供存储动态库的文件夹

                   /usr/include 系统提供存储头文件的文件夹
                   gcc -static 源文件名 -l 库文件名 -o 生成的可执行文件夹

         

;