2.常用的预处理指令、环境变量以及库文件的使用

1.常用的预处理指令

1.1 复习C语言中的指令,以‘#’开头,在预处理阶段中执行的指令

   #include ...
   #define  ...
   #undef                      取消宏定义
   #if
   #ifdef 
   #ifndef 
   #elif
   #else

   #endif

1.2 学习新的预处理指令
   #line     整数n----------------------------------------将下一行的行号变成n,主要用于确保产生错误的行号保持不变
   #warning     字符串---------------------------------主要用于在调试阶段产生警告信息
   #error   字符串---------------------------------------主要用于在错误阶段产生错误信息
   
   #pragma GCC dependency 文件名 -----------当前文件依赖于指定的文件名,如果指定文件的最后一次修改时间晚于当前文件,则产生警告信息 ;
   #pragma GCC poison 标识符-------------------主要用于将指定的标识符设置为毒药,一旦使用则产生错误信息
   #pragma pack(n)------------------------------------用于调整结构体的对齐和补齐方式为n的整数倍

                                                                                  主要便于存取数据的操作执行效率更高一些,而调整结构体的对齐和补齐方式主要为了节省内存空间。



注意:#if-----主要用于在编译链接阶段进行条件的判断

            if   -----主要用于可执行文件的阶段进行条件判断


1.3.预定义宏
   __BASE_FILE__   %s
   __FILE__   %s---------------主要用于获取当前宏所在的文件名称
   __LINE__   %d--------------主要用于获取当前宏所在的行号
   __FUNCTION__ %s
   __DATE__    %s------------主要用于获取当前宏所在文件的最后一次编译变异的日期
   __TIME__    %s-------------主要用于获取当前宏所在文件的最后一次编译变异的时间


2.环境变量的概念和使用
2.1 基本概念
   环境变量一般是指在操作系统中用来指定操作系统运行环境/应用程序环境的一些变量

   Path就是一个环境变量,一般来说,应用程序的执行需要带上路径才可以运行,而定义在环境变量Path中的路径系统会自动识别,因此对应的应用程序只需要程序名就可以运行


2.2 Unix/linux系统中的配置
   echo 字符串 
  => 字符串原样输出,回显
   echo $SHELL
  => 获取SHELL的值,进行回显
   echo $PATH
  => 获取PATH的值,进行回显打印


   export PATH=$PATH:.
      $PATH - 表示获取环境变量PATH中原来的数值
      :     - 多个路径之间的分隔符
      .     - 当前目录的路径
   表示将当前目录的路径追加到PATH的环境变量值中
   (一次性的,只是针对当前终端生效)


   vi ~/.bashrc,打开文件,在文件的最后增加代码:
       export PATH=$PATH:.
       export PS1='\W$' 
      => 表示终端的提示符只显示一个单词,使用$结尾
   source ~/.bashrc
   => 使得配置文件立即生效


2.3 编程相关的环境变量
   C_INCLUDE_PATH/CPATH --------- C头文件的附加搜索路径
   CPLUS_INCLUDE_PATH ------------C++头文件的附加搜索路径
   LIBRARY_PATH ------------------------- 链接库文件时查找的路径,主要解决编译时链接找不到库文件(即能放静态库又能放共享库)的问题(执行gcc时找不到库文件)
   LD_LIBRARY_PATH ------------------- 运行时查找共享库的路径,主要解决运行时链接找不到库文件的问题(运行时找不到库文件)


2.4 头文件的查找方式 
(1)#include <...>
   表示去系统默认的路径中查找该头文件
   /usr/include/stdio.h  
(2)#include "..."
   表示优先在当前工作目录下查找该头文件
(3)配置环境变量
   export CPATH=$CPATH:..  => 一次性
(4)使用编译选项 -I(建议使用)
   gcc/cc *.c -I 头文件的路径
   gcc/cc *.c -I ..




3.库文件的概念和使用
3.1 库文件的概念
   为了调用者使用的方便,一般并不会直接提供对应的.c文件或者.o文件,而是根据具体的功能模块,将对应的多个.o文件打包一个/多个库文件,给调用者提供库文件和头文件即可
   库文件主要分成两种:静态库文件和共享库文件
静态库:本质上就是由若干个目标文件(.o)打包生成的.a文件
链接静态库的本质:就是将调用的代码指令复制到调用模块中,体现在最终的可执行文件中

共享库:本质上就是由若干个目标文件(.o)打包生成的.so文件

链接共享库的本质:并不是将被调用代码指令复制到调用模块中,而是将被调用代码指令在共享库中的相对地址复制到调用模块中,体现在最终的可执行文件中。


(1)静态库的特性
   a.静态库在使用时,直接把代码 复制到 目标文件中
   b.优点:不需要跳转,效率比较好;脱离静态库文件
   c.缺点:目标文件会比较大;修改和维护都不太方便。占用空间比较大,最终生成的可执行文件比较大,库中代码一旦修改则需要重新链接才能体现在最终的可执行文件中
(2)共享库的特性(在主流的商业开发中,以共享库为主)
   a.共享库在使用时,直接把代码对应的地址 复制过来
   b.优点:目标文件比较小;修改和维护都比较方便
   c.缺点:需要跳转,效率比较低;不能脱离共享库文件
(3)基本命令
   ldd a.out => 表示查看a.out所链接的共享库信息
   gcc/cc -static xx.c => 表示以静态库方式进行处理
       比较发现,静态库方式生成的文件比较大


3.2 静态库的生成和使用步骤
(1)静态库的生成步骤
   a.编写源代码(xxx.c文件)
     vi add.c文件
   b.只编译不链接生成目标文件(xxx.o文件)
     gcc/cc -c add.c
   c.生成静态库文件
     ar -r/*插入*/ lib库名.a 目标文件
     ar -r  libadd.a add.o
注意:
   静态库文件名的名字规则:以lib开头,以.a结尾
   静态库文件名和库名是不同的概念,库名没前缀和后缀


(2)静态库的使用步骤
   a.编写测试源代码(xxx.c)
     vi main.c文件
   b.只编译不链接生成目标文件(xxx.o)
     gcc/cc -c main.c
   c.链接测试文件和静态库文件,链接的方式有三种:
     1)直接链接
       cc main.o libadd.a
     2)使用编译选项进行链接(掌握)
       gcc/cc main.o -l 库名 -L 库文件所在的路径
       gcc/cc main.o -l add -L .
     3)配置环境变量LIBRARY_PATH
       export LIBRARY_PATH=$LIBRARY_PATH:.
       gcc/cc main.o -l add


3.3 共享库的生成和使用步骤
(1)共享库的生成步骤
   a.编写源代码(xxx.c)
     vi add.c文件
   b.只编译不链接生成目标文件(xxx.o)
     gcc/cc -c -fpic add.c     /*-fpic 小模式,代码少,生成位置无关吗也就是生成相对地址*/
   c.生成共享库文件
     gcc/cc -shared 目标文件(xxx.o) -o lib库名.so
     gcc/cc -shared/*共享*/ add.o -o libadd.so
(2)共享库的使用步骤
   a.编写测试源代码(xxx.c)
     vi main.c文件
   b.只编译不链接生成目标文件(xxx.o)
     gcc/cc -c main.c
   c.链接测试文件和共享库文件,链接的方式有三种:
     1)直接链接
       cc main.o libadd.so
     2)使用编译选项进行链接(掌握)
       gcc/cc main.o -l 库名 -L 库文件所在的路径
       gcc/cc main.o -l add -L .
     3)配置环境变量LIBRARY_PATH(解决的是链接是找不到库文件的方式)
       export LIBRARY_PATH=$LIBRARY_PATH:.
       gcc/cc main.o -l add


注意:
(1)共享库的使用要求配置环境变量LD_LIBRARY_PATH的值,主要解决运行时找不到共享库的问题
   export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.(解决的是,运行时找不到库文件的方式)

(2)如果有一个静态库和一个共享库的库名相同,通过   gcc/cc main.o -l 库名 -L 库文件所在的路径   的方式链接,系统默认链接的是共享库,若想强制运行静态库则需要加上-static




3.4 共享库的动态加载

 注意:编译链接时需要增加选项: -ldl

(1)dlopen函数

   #include <dlfcn.h> 
   void *dlopen(const  char  *filename,int flag);
第一个参数:字符串形式的共享库文件名
第二个参数:标志
   RTLD_LAZY - 延迟加载
   RTLD_NOW - 立即加载
返回值:通用类型指针,
    成功返回句柄,暂时理解为首地址,失败返回NULL
函数功能:主要用于打开和加载共享库文件


(2)dlerror函数
   char *dlerror(void);
函数功能:
   主要用于获取dlopen等函数调用过程发生的最近一个错误的详细信息,返回NULL则表示没有错误发生


(3)dlsym函数
   void *dlsym(void *handle,const char *symbol);
第一个参数:句柄,也就是dlopen函数的返回值
第二个参数:字符串形式的符号,表示函数名
返回值:成功返回函数在内存中的地址,失败返回NULL
函数功能:
   主要用于根据句柄和函数名获取在内存中的地址


(4)dlclose函数
   int dlclose(void *handle);
函数功能:
   主要用于关闭参数handle所指定的共享库,成功返回0,失败返回非0,当共享库不再被任何程序使用时,则回收共享库所占用的内存空间



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值