• 编译器背后的故事


    一、gcc生成.so动态库和.a静态库

    我们通常把一些公用函数制作成函数库供其他程序使用。函数库又分为静态库动态库

    静态库:在程序编译是会被连接到目标代码中,程序运行是将不再需要该静态库。步骤如下:

    1. 无论是静态库还是动态库都是由.o文件创建的,因此我们必须将源程序.c文件通过gcc先编译成.o文件

      gcc -c main1.c sub1.c sub2.c
      
    2. 由.o文件创建静态库。静态库文件名的命名规范是以lib为前缀,紧跟着静态库名,扩展名为.a。创建静态库用ar命令。

      ar -crv libsub2.a sub1.o sub2.o
      

    3. 在程序中使用静态库。

      gcc -o test3 main1.o libsub.a
      

    动态库:在程序编译时并不会被连接到目标代码中,而是在程序运行时才被载入,因此在程序运行时还需要动态库存在。步骤如下:

    1. 先生成.o文件

    2. 由.o文件创建动态库文件,命名规范和静态库类似,扩展名为.so

      gcc -shared -fpic -o libsub.so sub1.o sub2.o
      

    1. 在程序中使用动态库

      gcc main1.c libsub.so -o test4
      

    总结注意:上述源程序代码main1.c,sub1.c,sub2.c为下

    //main1.c
    #include"sub1.c"
    #include"sub2.c"
    #include<stdio.h>
    int main(){
    	int a,b,d,s;
    	a = 8;
    	b = 24;
    	d = x2x(a,b);
    	s = x2y(b,a);
    	printf("The result one is =%d
    ",d);
    	printf("The result two is =%d
    ",s);
    	return 0;
    }
    //sub1.c
    extern int x2x(int a,int b){
    	int r;
    	r = a+b;
    	return r;
    }
    //sub2.c
    extern int x2y(int a,int b){
    	int r;
    	r = a*b;
    	return r;
    }
    

    (1)动态库和静态库同时存在时,优先使用动态库

    (2)当静态库和动态库同名时,gcc命令会优先使用动态库,默认去连/usr/lib和/lib等目录下的动态库,这时需要将.so文件复制到目录/usr/lib下即可 sudo cp ***.so /usr/lib

    二、gcc背后的故事

    gcc编译过程分为四个阶段进行:预处理(也称预编译,Preprocessing)、编译(Compilation)、汇编(Assembly)和连接(Linking)

    1)预处理

    预处理主要包括以下过程(1)将所有的#define删除,并且展开所有的宏定义,并且处理所有的条件预编译指令,比如#if #idfef #elif #else #endif等(2)处理#include预编译指令,将被包含的文件插入到该预编译指令的位置。(3)删除所有注释“//” “/* */ ”。(4)添加行号和文件标识,以便编译时产生调试用的行号及编译错误警告行号。(5)保留所有的#pragma编译器指令,后续编译过程需要使用它们。

    预处理命令如下(本文章均用test.c):

    gcc -E test.c -o test.i 或 gcc -E test.c
    

    gcc的 -E选项,可以让摆一起在预处理后停止,并输出预处理结果。在本例中,预处理结果就是将stdio.h文件中的内容插入到test.c中

    2)编译

    编译过程就是对预处理完的文件进行一系列的词法分析、语法分析、语义分析及优化后生成相应的汇编代码。

    编译命令如下:

    gcc -S test.i -o test.s
    

    gcc的 -S选项,表示在程序编译期间,在生成汇编代码后,停止,-o输出汇编代码文件

    3)汇编

    汇编过程调用对汇编代码进行处理,生成处理器能识别的指令,保存在后缀为.o的目标文件中。注:当程序有多个源代码文件构成时,每个文件都要先完成汇编工作生成.o文件才能进行下一步链接工作

    gcc -c test.s -o test.o
    

    将生成的汇编代码文件编译为目标文件

    4)链接

    链接分为静态链接和动态链接。区别如下

    (1)静态链接是指在编译阶段直接把静态库加入到可执行文件中去,其中可执行文件会比较大。

    (2)动态链接是指链接阶段仅仅只加入一些描述信息,而程序执行时再从系统中把相应动态库加载到内存中去,相对来说可执行文件会小很多

    gcc test.o -o test
    

    过程

    生成的各种文件

    静态库和动态库生成的文件大小比较

    as汇编编译器针对的是AT&T汇编代码风格,Intel风格的汇编代码则可以用nasm汇编编译器编译生成执行程序。请在ubuntu中下载安装nasm,对示例代码“hello.asm”编译生成可执行程序,并与“hello world”C代码的编译生成的程序大小进行对比。

    三、第三方库的了解

    1)了解Linux 系统中终端程序最常用的光标库(curses)的主要函数功能,写出几个基本函数名称及功能;

      initscr():初始化curses库和ttty。(在开始curses编程之前,必须使用initscr()这个函数来开启curses模式)
    
      endwin():关闭curses并重置tty。(结束curses编程时,最后调用的一个函数)
    
      cbreak():开启cbreak模式,除了 DELETE 或 CTRL 等仍被视为特殊控制字元外一切输入的字元将立刻被一一读取
    
      crmode():使得终端进入到cbreak模式。
    
      move(y,x): 将游标移动至 x,y 的位置. 
    
      getyx(win,y,x): 得到目前游标的位置. (请注意! 是 y,x 而不是&y,&x ) 
    
      clear() and erase(): 将整个萤幕清除. (请注意配合refresh() 使用)
    

    2)在 win10 系统中,“控制面板”-->"程序"--->"启用或关闭Windows功能",启用 "telnet client" 和"适用于Linux的Windows子系统"(后面会使用)。 然后打开一个cmd命令行窗口,命令行输入 telnet bbs.newsmth.net,以游客身份体验一下即将绝迹的远古时代的 BBS (一个用键盘光标控制的终端程序)。

    3)在Ubuntu中用 sudo apt-get install libncurses5-dev 安装curses库,请说明 头文件(比如curses.h)和库文件都被安装到哪些目录中?

      头文件(比如curses.h)和库文件被分别安装在/usr/include/和/usr/lib/下
    

    4)Linux 环境下C语言编译实现贪吃蛇游戏

  • 相关阅读:
    我的第一个项目--总结
    c++中的继承
    指针带来的意想不到的功能紊乱
    一个很难发现的内存泄漏
    我的第一个项目--迭代开发总结
    内存访问冲突问题(非法内存访问)
    Debug Assertion Failed mfc140ud.dll
    javaweb 开发总结五-----servlet开发(一)
    javaweb学习总结四---http协议
    Tomcat服务器学习和使用二·
  • 原文地址:https://www.cnblogs.com/Zzxin/p/13831671.html
Copyright © 2020-2023  润新知