Linux环境编程笔记1

gcc支持的预处理指令:

#include      // 将指定文件的内容插至此指令处
#define       // 定义宏
#undef        // 删除宏
#if           // 判定
#ifdef        // 判定宏是否已定义
#ifndef       // 判定宏是否未定义
#else         // 与#if、#ifdef、#ifndef结合使用
#elif         // else if多选分支
#endif        // 结束判定
##            // 连接宏内两个连续的字符串
#             // 将宏参数扩展成字符串字面值
#error        // 预处理时产生错误,结束预处理
#warning      // 预处理时产生警告信息
#pragma       // 提供额外信息的标准方法,可用于指定平台
#pragma GCC dependency <文件>     // 若<文件>比此文件新则产生警告
#pragma GCC poison <标识>         // 若出现<标识>则产生错误
#pragma pack(1/2/4/8)             // 按1/2/4/8字节对齐补齐
#line                             // 指定行号

gcc预定义的宏:

void printf_macro (void) 
{
    printf ("__FILE__          : %s\n", __FILE__);      //获取当前文件名
    printf ("__LINE__          : %d\n", __LINE__);      //获取行号
    printf ("__FUNCTION__      : %s\n", __FUNCTION__);  //获取函数名
    printf ("__func__          : %s\n", __func__);      //获取函数名
    printf ("__DATE__          : %s\n", __DATE__);      //获取日期(字符串)
    printf ("__TIME__          : %s\n", __TIME__);      //获取时间
    printf ("__cplusplus       : %d\n", __cplusplus);   //g++编译输出1;gcc编译输出0
}
通过修改配置文件设置:
Linux系统的修改方法
# 打开配置文件:
vi ~/.bashrc            # 只对当前用户用效
vi /etc/environment     # 对所有用户有效

# 在文件末尾添加内容:
export C_INCLUDE_PATH=<环境变量的内容>
C_INCLUDE_PATH=$C_INCLUDE_PATH:<追加新的内容>
    
# 重新加载配置文件:
source ~/.bashrc
image.png
创建静态库:
# 编译出目标文件:
gcc -c xxx1.c
gcc -c xxx2.c
...

# 把目标文件打包成静态库文件
ar -r libxxx.a x1.o x2.o ...

# ar 是一个专门控制静态库的命令
    -r # 把目录文件合并成一个静态库,如果静态库文件已经存在则更新。
    -q # 向静态库中添加目标文件
    -t # 查看静态库中有哪些目标文件
    -d # 从静态库中删除目标文件
    -x # 把静态库展开为目标文件 
使用静态库:
# 方法1、直接调用,把共享库当作目标文件一样,与调用者的目标文件一起合并出可执行文件。
gcc main.c libxxx.a

# 方法2、通过设置LIBRARY_PATH环境变量来指定库的路径,通过-l参数来指定库名
gcc main.c -lxxx

# 方法3、通过gcc -L参数来指定库的路径,通过-l参数来指定库名
gcc main.c -L<PATH> -lxxx
创建动态库:
# 编译出目标文件,-fpic编译出位置无关代码,在代码中使用相对地址,这样共享库就可以加载到内存的任何位置。
gcc -c -fpic xxx1.c
gcc -c -fpic xxx2.c
...

# 把目标文件打包成共享库:
gcc -shared xxx1.o xxx2.o ... -o libxxx.so
使用动态库:
# 方法1、直接调用
gcc main.c libxxx.so

# 方法2、通过设置LIBRARY_PATH环境变量来指定库的路径,需要通过-l来指定库名
gcc main.c -lxxx 
    

# 3、通过gcc -L参数来指定库的路径
gcc main.c -L<PATH> -lxxx

# 注意1:如果执行无法运行,需要检查操作系统是否能加载动态库,检查LD_LIBRARY_PATH环境变量
# 注意2:如果静态库和共享库同时存在,优先使用共享库,通过-static可以指定使用静态库。

静态库的优点:

使用方便,运行速度快:
在链接目标文件生成程序时,只需要把静态库与目标文件一起编译,编译器就会把目标文件中使用到的静态的内容拷贝到程序中,程序在运行时就不需要静态库了。

静态库的缺点:

更新麻烦:
使用了相关静态库的程序需要重新编译,如果是应用程序,用户就需要重新下载。
浪费内存:
代码的拷贝造成了冗余,造成内存的浪费。

动态库的缺点:

在链接目标文件时,虽然动态库需要与使用它的目标文件一起编译,但编译器只是记录被调用的内容(函数、变量)在动态库中的位置,生成的程序中只有跳转到动态库的相关指令,当执行到动态库的相关内容时,才跳转到动态库所在的内存中执行,完成后再返回。
运行速度慢:
使用动态库程序需要在程序和动态库中来回跳转,因此要比使用静态库的程序运行的速度慢。
程序无法执行:
如果系统找不到相应的动态库,那么程序就无法运行(Windows系统经常提示的xxx.dll文件缺失,程序无法运行),产生这种错误的原因有很多,如:环境变量配置错误,动态库文件存储位置错误。

总结:当一个模块不会再发生改变,并且执行速度有一些要求,适合把它封装成静态库。

动态库的优点:

节约内存:
使用的动态库只需被系统加载一次,不同的程序都可以使用到内存中的动态库,因此节约了很多内存,由于多个程序可共享使用一个动态库,所以动态库也叫共享库。
更新方便:
如果动态库中的函数格式没有变化(返回值、函数名、参数列表),而只是函数中的业务逻辑代码发生变化,那么只需要重新编译动态库即可,不需要重新编译相关的可执行文件,这也是某些应用程序可以自动更新的原因。

总结:随着计算机性能的不断提升,弥补了动态库运行速度慢的缺点,再加上它能节约内存、更新方便,最主要的是计算机硬件一直在升级,所以就导致大多数代码需要不断的升级,因此我们大多数情况下把模块封装成动态库。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容