Linux文件编程
为什么需要分文件编程

对一个需求进行功能责任划分
方便调试
让主程序更加整洁


如何分文件编程
如现在一个计算器的需求

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

double add(double a,double b)
{
    return a+b;
}

double reduce(double a,double b)
{
    return a-b;
}

double ride(double a,double b)
{
    return a*b;
}

double except(double a,double b)
{
    return a/b;
}

int main(int argc,char *argv[])
{
    if(argc < 4){
        printf("missing parameter ->+-*/ ->a ->b to a+b\n");
        exit(-1);
    }
    double a = atof(argv[1]);
    double b = atof(argv[3]);
    double ret;

    if(strcmp(argv[2],"+") == 0){
        ret = 0;
        ret = add(a,b);
    }

    if(strcmp(argv[2],"-") == 0){
        ret = 0;
        ret = reduce(a,b);
    }

    if(strcmp(argv[2],"x") == 0){
        ret = 0;
        ret = ride(a,b);
    }

    if(strcmp(argv[2],"/") == 0){
        ret = 0;
        ret = except(a,b);
    }

    printf("result is %0.2f\n",ret);
    return 0;
}


我们将加减乘除的功能进行划分成四个.c文件,让主程序更加简洁

add.c

double add(double a,double b)
{
    return a+b;
}

add.h

double add(double a,double b); //注意分号

reduce.c

double reduce(double a,double b)
{
    return a-b;
}

reduce.h

double reduce(double a,double b);

ride.c

double ride(double a,double b)
{
    return a*b;
}

ride.h

double ride(double a,double b);

except.c

double except(double a,double b)
{
    return a/b;
}

except.h

double except(double a,double b);

主函数:my_main.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "add.h"
#include "reduce.h"
#include "ride.h"
#include "except.h"


int main(int argc,char *argv[])
{
    if(argc < 4){
        printf("missing parameter ->+-*/ ->a ->b to a+b\n");
        exit(-1);
    }
    double a = atof(argv[1]);
    double b = atof(argv[3]);
    double ret;

    if(strcmp(argv[2],"+") == 0){
        ret = 0;
        ret = add(a,b);
    }

    if(strcmp(argv[2],"-") == 0){
        ret = 0;
        ret = reduce(a,b);
    }

    if(strcmp(argv[2],"x") == 0){
        ret = 0;
        ret = ride(a,b);
    }

    if(strcmp(argv[2],"/") == 0){
        ret = 0;
        ret = except(a,b);
    }

    printf("result is %0.2f\n",ret);
    return 0;
}


gcc编译时,对于头文件和和库

‹›:优先去/usr/include/ 寻找该头文件
“ ”:优先在当前路径 寻找该头文件
-L 路径:指定库的路径
-I 路径:指定头文件的路径


Linux库
本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行,就是将源代码转变成二进制格式的源代码,这就是相当于是对这部分的代码进行了加密,别人可以使用这个库,但是看不见库里面的内容,不需要提供.c的分文件

使用库的好处:程序函数库可以使整个程序更加模块化,更容易重新编译,而且更方便升级Linux中的静态库。

Linux静态库
在目标程序执行前(编译的时候)就加入到目标程序中去了

优点
静态库在编译的时候就被打包到应用程序中,所以其加载的速度快
发布程序的时候无需提供静态库,因为已经在app中,移植方便


缺点
链接时完整的拷贝到可执行文件中,被多次使用就会有多份冗余拷贝
更新,部署,发布麻烦


如何使用静态库
使用静态库类似于分文件编程:

将分文件编译成.o文件 gcc xxx1.c xxx2.c xxx3.c -c

生成xx1.o xx2.o xx3.o文件

将.o文件编译成静态库ar rcs libxxx.a xx1.o xx2.o xx3.o

生成静态库libxxx.a

使用静态库gcc 主程序.c -lxxx



Linux动态库
是在目标程序执行时动态(临时)由目标程序去调用。

优点
链接时不复制,程序运行时由系统动态加载到内存,供程序调用,系统只加载一次,多个程序可以共用,节省内存
程序升级简单,因为app中没有库的源代码,升级之后只要库的名字不变,函数名与及参数不变,只是做了优化,就能加载成功


缺点
加载速度比静态库慢
发布程序时需要提供依赖的动态库


如何使用动态库
将分文件编译成.o文件 gcc xxx1.c xxx2.c xxx3.c -c

生成xx1.o xx2.o xx3.o文件

将.o文件编译成动态库gcc -shared xx1.o xx2.o xx3.o -o libxxx.so

生成动态库libxxx.so
使用动态·库gcc 主程序.c -lxxx
动态库要添加到/usr/lib底下或者执行可执行文件时通过环境变量添加动态库的搜索路径,否则在执行可执行文件时会报错



方式1,动态库添加到/usr/lib底下:sudo cp libxxx.so /usr/lib
方式2,通过环境变量添加动态库的搜索路径:export LD_LIBRARY_PATH=“动态库所在路径”


软链接和硬链接
软链接
软链接也称为符号链接(Symbolic Link),软链接文件类似于windows的快捷方式,它实际上是一种特殊的文件,在符号链接中,文件实际上是一个文本文件,其中包含的有另一个文件的位置信息。
创建一个软链接:ln -s 要被链接的文件 软链接文件名


硬链接
硬连接指通过索引节点来进行连接。在Linux的文件系统中,保存在磁盘分区中的文件不管是什么类型都给它分配一个编号,称为索引节点号(Inode Index)。在Linux中,多个文件名指向同一索引节点是存在的。一般这种连接就是硬连接。硬连接的作用是允许一个文件拥有多个有效路径名,这样用户就可以建立硬连接到重要文件,以防止“误删”的功能。其原因如上所述,因为对应该目录的索引节点有一个以上的连接。只删除一个连接并不影响索引节点本身和其它的连接,只有当最后一个连接被删除后,文件的数据块及目录的连接才会被释放。也就是说,文件真正删除的条件是与之相关的所有硬连接文件均被删除。
创建一个硬链接:ln 要被链接的文件 软链接文件名