Unix like下gcc编译连接c/c++使用方法小结

来源:互联网 发布:java 1000以内的完数 编辑:程序博客网 时间:2024/05/22 10:47

1.在c/c++变成中,有源代码生成可执行文件需要四个阶段:

  • 预处理阶段(preprocess)
  • 编译阶段(compile)
  • 汇编阶段(assemble)
  • 连接阶段(link)

2.gcc的用法小结

gcc是由GNU计划维护的,是一个在Unix like系统下进行编译和连接的工具。

假设源文件是main.c,

(1)预处理阶段

这个过程包括了下面的步骤:
         >> 宏定义展开,所有的#define 在这个阶段都会被展开
         >> 预编译命令的处理,包括#if #ifdef 一类的命令
         >> 展开#include 的文件,像上面hello world 中的stdio.h , 把stdio.h中的所有代码合并到hello.c中
         >> 去掉注释

gcc -E main.c -o main.i   #产出的“预处理源代码”写入到main.i文件中

(2)编译阶段

编译阶段会进行语法分析和词法分析的地方, 将C/C++代码翻译成为 汇编代码, 这也是一个编译器最复杂的地方。

gcc -S main.i -o main.s  #输入文件是“预处理源代码”gcc -S main.c -o main.s  #输入文件是源代码
(3)汇编阶段

经过编译阶段,C/C++代码已经成为汇编代码了。在汇编阶段中,编译器会把汇编代码变成机器码(注意机器码还不是可执行文件)。比如经过gcc -c hello.c -o hello.o生成的hello.o就是机器码,可以直接用来作为静态链接库。

gcc -c main.c -o main.o    #输入文件是“源代码”gcc -c main.i -o main.o    #输入文件是“预处理源代码”gcc -c main.s -o main.o    #输入文件是“汇编码”

(4)链接阶段

        链接的过程,本质上来说是一个把所有的机器码文件组合成一个可执行的文件。上面汇编的结果得到一个.o文件, 但是这个.o要生成二执行文件只靠它自己是不行的。它还需要一堆辅助的机器码,帮它处理与系统底层打交道的事情,比如printf以及scanf所有在系统库。链接阶段是由链接器来负责,链接阶段主要完成符号解析和重定位两项工作。

        对于符号解析,符号包括了我们的程序中的被定义和引用的函数和变量信息。链接器符号解析过程,是试图将每一个程序中引用的符号与某一个目标文件(.o)的符号表中一个符号关联起来。

       对于重定向,经过上面的符号解析后,所有的符号都可以找到它所对应的某一个位置,但是不知道数据和代码在最后具体的位置,同时也不知道任何外部定义的符号的具体位置。在编译阶段,对于位置未知的符号,编译器会生成一个重定位表目,告诉链接器在将目标文件合并成可执行文件时候如何修改地址成最终的位置。

      关于动态链接库和静态链接库的介绍参见《linux下库的介绍与使用》

gcc main.c -o main    #输入文件是“源代码”gcc main.i -o main    #输入文件是“预处理源代码”gcc main.s -o main    #输入文件是“汇编码”gcc main.o -o main    #输入文件是“链接码”

备注,如上几个过程,如果没有加上-o指定输出文件的文件名,那么会默认的输出的控制台或者产出的文件使用一个默认的文件名。


3.gcc的几个重要选项的说明

       (1)-o file   ——将gcc命令处理的结果输出到文件中

         gcc -o file file_1.o file_2.o    命令执行后,将目标文件file_1.o和file_2.o链接生成可执行文件file

       (2)-lm       ——表示在编译自己的源文件的时候,将libm.so(应该相当于windows下的静态链接库或动态链接库)这个函数库加入进来。可以将-l看成是选项,表示引入某个函数库的意思。而m表示使用libm.so这个函数库,只是把lib以及.so省略了。

       (3)-L/path   ——和上面的-lm参数是有关联的,表示上面要引入的函数库在os中的路径,一条编译命令里面可以有多个-L/path参数。

       (4)-I/path     ——表示源码中include预处理中,include进来的文件在os中的路径,一条编译命令里面可以有多个-I/path参数。

PS.如果在使用gcc命令后直接跟着源文件,没有-o,那么表示将源码编译链接并直接生成了可执行文件(a.out)


4.举一个简单的例子来说明

/*文件名helloworld.c*/#include<stdio.h>int main(){        printf("Hello World!!!\n");        func_1();        float value = sin(3.14/2);        printf("value = %f\n",value);        return 0;}

/*文件名func_1.c*/#include<stdio.h>void func_1(){        printf("invoke func_1()...\n");}

说明,这个例子中包括了主程序与子程序的调用编译的场景,也包括调用外部函数库的场景。

编译和连接:

gcc helloworld.c func_1.c -lm -L/lib -L/usr/lib -I/usr/include
执行和结果:

./a.out


备注:编译链接时,加上-g选项后,才可以使用gdb来进行调试。



        

0 0