美文网首页
链接详解

链接详解

作者: iMikasa_ | 来源:发表于2021-11-10 15:30 被阅读0次

    多目标文件的链接

    为了使程序的模块化更强,代码更易于分类管理,有时需要将同类型的代码存储在一个文件中。这时每一个文件代表着一类函数代码。这些代码使用同样的资源,完成同样的操作。由于代码被划分为若干模块。这时就会导致多个C语言文件(模块)链接的问题

    代码示例:

    //test.c
    #include <stdio.h>
    #include "my_methods.h"
    
    int main(int argc, char const *argv[])
    {
        printf("和为:%d",add(4,3));
        my_printf();
        return 0; 
    }
    
    //my_methods.h
    int add(int a,int b);
    void my_printf();
    
    //my_methods.c
    #include <stdio.h>
    #include "my_methods.h"
    
    int add(int a,int b){
        return a+b;
    }
    void my_printf(){
        printf("hello my abilety is say hello");
    }
    
    • 在命令行窗口中编译该程序如下。
      gcc test.c my_methods.c -o main
    • 在命令行窗口中运行该程序如下。
      ./main
      image.png
      成功运行。。。

    接着我有些了一个程序是如下

    //test.c
    #include <stdio.h>
    
    // extern int add(int a,int b);
    // extern int sub(int a,int b);
    // extern int mul(int a,int b);
    // extern int div(int a,int b);
    // extern void my_printf(void);
    
    int main(int argc, char const *argv[])
    {
        printf("%d\n",add(4,2));
        printf("%d\n",sub(4,2));
        printf("%d\n",mul(4,2));
        printf("%d\n",div(4,2));
        my_printf();
        return 0;
    }
    
    //opera.c
    #include <stdio.h>
    
    char str[] = "i am a string!";
    
    int add (int a,int b){
        return a+b;
    }
    int sub(int a,int b){
        return a-b;
    }
    int mul(int a,int b){
        return a*b;
    }
    int div(int a,int b){
        return a/b;
    }
    void my_printf(){
        printf("%s\n",str);
    }
    

    紧接着编译,发现编译有警告,但是能正常运行


    image.png

    这是因为编译器在处理 add等 函数调用时没有找到 add 函数的原型,只能根据 add(4, 2) 函数调用“推测”,若是把test.c中的注释去掉就不会有问题了。

    extern

    extern 的字面意思是“外部的”,它也是 C 语言中的一个关键字,表示“外部符号”。你已经知道 C 语言编译器需要知道函数的原型,所以在 main.c 中,正确的做法应该是:

    #include <stdio.h>
    extern int add(int a, int b);
    // 或 int add(int a, int b);
    int main()
    {
        char i = 7;
        printf("3+4=%d\n", add(3, 4));
        printf("3+7=%d\n", add(3, i));
        return 0;
    }
    

    这样编译器就知道 add 函数的原型了,也知道它来自于外部文件。实际上,函数声明中的 extern 也可以不写,不过不写 extern 仍然表示 add 函数是外部符号。

    当然extern也可以修饰变量,就像这样extern int a ;
    引入外部变量时,extern 不能省略。extern int a;不是定义变量,因此不会为 cnt 分配空间。当然如果你在外部是已经给这个变量初始化赋值的话,你在引入外部变量在赋值,就会编译报错,是非法的

    如果不希望外界使用本文件里定义的函数,或者变量,该怎么办呢?答案是使用 static 关键字。以前我们使用过 static 来定义静态变量,它其实还表示变量或者函数属于“内部符号”,有 static 修饰的全局变量和函数在外部文件中都是不可见的。

    Linux 静态库和动态库

    一个“程序函数库”简单的说就是一个文件包含了一些编译好的代码和数据,这些编译好的代码和数据可以在事后供其他的程序使用。程序函数库可以使整个程序更加模块化,更容易重新编译,而且更方便升级。

    程序函数库可分为3种类型:静态函数库(static libraries)、共享函数库(shared libraries)、动态加载函数库(dynamically loaded libraries):

    1、静态函数库,是在程序执行前就加入到目标程序中去了 ;

    2、动态函数库同共享函数库是一个东西(在linux上叫共享对象库, 文件后缀是.so )

    静态库

    步骤

    1.编写源代码文件,生成目标文件
    gcc -c <源代码文件,如main.c>
    2.归档目标文件,得到静态库

    我们使用ar将目标文件归档,如下

    ar crv 归档文件 目标文件列表
    ar crv libmylib.a my_math.o

    我们就得到了libmylib.a,这就是我们需要的静态库。
    上述命令中 crv 是 ar的命令选项:
    c 如果需要生成新的库文件,不要警告
    r 代替库中现有的文件或者插入新的文件
    v 输出详细信息

    通过 ar t libmylib.a 可以查看 libmylib.a 中包含的目标文件。
    可以通过 ar --help 查看更多帮助。
    注意:我们要生成的库的文件名必须形如 libxxx.a ,这样我们在链接这个库时,就可以用 -lxxx。
    反过来讲,当我们告诉编译器 -lxxx时,编译器就会在指定的目录中搜索 libxxx.a 或是 libxxx.so。

    3.编写对应的头文件,测试静态库

    gcc test.c -L. -lmylib
    

    将会生成a.out,通过 ./a.out 可以运行该程序。说明我们的静态库能正常工作。

    上面的命令中 -L. 告诉 gcc 搜索链接库时包含当前路径, -lmylib 告诉 gcc 生成可执行程序时要链接 libmylib.a。

    共享库

    步骤

    1.编写源文件
    2.编译生成共享库
    gcc -fPIC -shared -o libmax.so max.c

    参考

    https://www.cnblogs.com/hzh1024n/archive/2009/09/17/1568357.html
    https://blog.csdn.net/u012662731/article/details/53783401
    https://www.cnblogs.com/sunsky303/p/7731911.html
    https://www.jianshu.com/p/74003997b48c

    有待补充

    相关文章

      网友评论

          本文标题:链接详解

          本文链接:https://www.haomeiwen.com/subject/pkebzltx.html