• c语言的链接(静态链接和动态链接)以及a.out的简述


           链接过程分类两种,动态链接和静态链接。如果函数库的一份拷贝是可执行文件的物理组成部分,则为静态链接,动态链接生成的可执行文件只包含了文件名,在运行时,程序会自动寻找所需要的函数库。函数只有在运行的时候才会被解析调用,它是在main函数之前就决定好了。

            静态链接与动态链接的优缺点就很明显了。静态链接提前把需要的函数都载入到了可执行文件中,所有更加独立,速度更快。缺点就是程序更新不方便,生成的可执行文件更大。动态链接有点更多了,它可以随时更新自己的功能,而不需要重新编译,生成的文件更小。

             动态链接被发明的原因之一是为了把程序和特定的函数库版本分离,也就是标准接口固定,后续的函数库迭代不受版本的影响。


    1.动态链接的优点

    (1).相同条件下,可执行文件更小。因为动态链接只有在需要的时候,才把对应的函数和数据载入到进程。

    (2).所有动态链接到某个特定函数库的可执行文件在运行时共享该函数库的一个单独拷贝。这句话有点拗口,简单来讲,就是共享库的函数只占据一份空间,不会再每一个需要的地方都占用一份,提高了空间利用率。

    (3).动态链接允许用户在运行时选择需要执行的库函数版本。动态链接使得函数库的版本升级更为容易,新的函数版本可以随时发布,只要安装到操作系统中,旧的程序就能自动获得新版本函数库的优点而不需要重新链接。


    2.动态链接的一般细节

           动态链接会关注函数所在的位置,所有不要改动原本动态函数所在的位置,比如C语言的动态库一般都在libc中。当然,我们也可以自己决定位置,需要在链接的时候说明。

           静态库被称为archive,通过ar(一种生产工具)来创建和更新。静态库约定在它们的文件名中使用.a的扩展名。

            还有一种技术,介于静态和动态之间,它是静态共享库,在生命周期内,它们的地址始终固定,可以直接绑定到操作系统中,但是由于限制颇多,需要专门的操作系统支持,这里只提及一句。

            动态链接库由链接编辑器ld创建,动态链接库的文件扩展名为.so(shared object)。

            回忆一下编译的四个阶段,预处理->编译->汇编->链接

            (1).预处理:替换掉预处理命令,生成.i的文件

            命令:gcc -E 文件名 -o 指定生成文件名

           (2).编译:生成汇编文件,生成.s的文件

            命令:gcc -S 文件名.i -o 指定生成的文件名

           (3).汇编:生成二进制文件,生成.o的文件

            命令:gcc -c 文件名 -o 指定生成的文件名

           (4).链接:生成可执行文件,Linux中生成的默认文件名叫a.out,在window中会生成.exe

            命令: gcc 文件名 -o 指定生成的文件名

         动态链接生成的文件名叫.so或者.dll(windows系统),而静态文件的扩展名是.a


    3.动态编译的流程

            假设我们有如下几个文件:main.c test.h test.c

    显然main.c是主函数,test.c是集成了许多函数的功能函数,让函数在运行期间调用test.c,编译过程如下:

          1.gcc test.c -shared -o test.dll

    生成test.dll动态文件,也可以取名test.so

           2.gcc main.c test.dll -o test.exe

    生成test.exe可执行文件。

    知道这两个步骤就差不多了,需要注意的是,可以通过-L来指定文件路径。


    4.a.out的段

                 使用size命令,查看a.out文件,它会给出三种类型数据的大小,分别是text,data,bss

    data段(数据段):存放初始化后的全局以及静态变量

    text段(文本段):可执行文件的指定,比如加减乘除,调用函数等等

    bss段:保存没有值的变量。

    局部变量不进入a.out,它们是在运行时创建的

    举个例子

    1. char str[100];
    2. static double a;
    3. int b = 10;
    4. static double pi = 3.14;
    5. int main()
    6. {
    7. int i = 3, j, *ptr;
    8. ptr = malloc(100*sizeof(int));
    9. ptr[3] = 3;
    10. return 0;
    11. }

    char str[100];
    static double a;

    放在bss中

    int b = 10;
    static double pi = 3.14;

    放在data中

        int i = 3, j, *ptr;

    在运行的时候自动创建,并没有保存在a.out中

        ptr = malloc(100*sizeof(int));
        ptr[3] = 3;

    这种指令放在text中
     

    补充:C语言运行时,操作系统对a.out的操作

    主要是使用mmap函数,将a.out的各个段映射到进程空间之中,每个段都有不同的权限,有的是可读可执行,有的是可读可写,操作系统还会根据情况分配一些栈空间和堆空间,给临时变量或者malloc这样的函数使用,bss和data其实被映射到了一起,都叫数据段,

           

  • 相关阅读:
    BOSS直聘新财报:用户、技术两手抓
    TiDB 工具下载
    leetcode:828. 统计子串中的唯一字符【贡献题 + 记录同一个c的下标 + 分别记录每个c的贡献】
    11.10
    Java Map转换工具类
    树莓派基础 | 总结记录树莓派学习过程中的一些操作
    intel cpu core/“酷睿”系列发展史,供组装机的朋友们参考
    平时整理的一些小算法
    浙大MPA常规批复试上岸经验分享
    【猿灰灰赠书活动 - 06期】- 【计算机考研书单——408专属】
  • 原文地址:https://blog.csdn.net/weixin_42581560/article/details/133579255