UBuntu12.04下用gcc编译c文件过程详解

时间:2022-06-03 00:56:42

一  文件准备

      因为正好要做作业,所以用vim写了如下两个文件:(是一个处理字符串的程序,不要在意,和gcc解释没什么关系。)放在~/Downloads

      1. reverse.h         

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

void reverse(char *str);

      2. reverse.c

#include"reverse.h"

void reverse(char *str)
{
int i;
int len;
char c;
len=strlen(str);
for(i=0;i<len/2;i++)
{
c=*str+i;
*(str+i)=*str+len-i-1;
*(str+len-i-1)=c;
}
}

int main()
{
char str[1024];
printf("Give me a word to reverse:\n");
scanf("%s",str);
reverse(str);
printf("REVERSED: %s\n",str);
return 0;
}
        文件如下:
UBuntu12.04下用gcc编译c文件过程详解


二  一步式gcc编译C文件

        在终端输入如下命令:

gcc reverse.c -o reverse -I ./
        可以看到文件夹里出现了一个reverse可执行文件,如图:

UBuntu12.04下用gcc编译c文件过程详解

        在终端输入如下命令:

./reverse
        运行结果如图:

UBuntu12.04下用gcc编译c文件过程详解

        如上 -o选项就是链接,后面加上生成的可执行文件的名字,不输入默认为 a.out 。所有步骤都隐式被悄悄搞定了,生成的文件用完都删掉了。-I 选项后面加上 reverse.h 的路径,即告诉编译器在这个目录下找头文件,因为在 reverse.c 中用到了 reverse.h 。如果它们在同一个目录下是可以省略的。

        也可以用如下形式一步搞定,终端输入:

rm reverse /*删掉刚才生成的可执行文件,此时终端已经进入Downloads*/
gcc reverse.c -o reverse.o
./reverse.o
        文件列表如下:

UBuntu12.04下用gcc编译c文件过程详解

        多了一个reverse.o。.o文件是目标文件类型,可以直接运行,因为已经完成了所有步骤,只是跟上一个的名字不一样而已就类似a.out。(注意此时没有-c选项,也可以把-o后面直接加reverse生成菱形的可执行文件) 如果在reverse.o属性栏中把名称改成 reverse.out 就会变成 reverse 的类型,即可执行文件。如图:

UBuntu12.04下用gcc编译c文件过程详解

三  分步详细解析

        gcc编译C文件一共四步,预处理(Preprocess),编译(Compilation),汇编(Assembly)和链接(Linking)

    1. 预处理(Preprocess)

            预处理是预处理中会展开以#起始的行,包括#if、#ifdef、#if ndef、 #else 、 #elif 、 # endif、#define、#include、#line、 #error、#pragma以及单独的#。其实就是把除了函数(包括main)以外的东西都展开成指定的形式,比如加上行号等,并将头文件里包含的东西所对应的文件(包括子文件夹)也都写入进去以便调用。同时也会把写在文件里的注释都删掉。

            在终端输入:

//rm reverse.out  删除刚才生成的reverse.out
gcc -E reverse.c -o reverse.i
            可以看到生成一个名字为reverse.i的文件。

UBuntu12.04下用gcc编译c文件过程详解

            通过vim可以看到一共是1136行,多加了上千行,都是预处理做的事情。

UBuntu12.04下用gcc编译c文件过程详解

            -E是仅激活预处理程序,将生成的信息放入reverse.i。如果不写 -o reverse.i 就会生成到终端显示。相当于重定向。

    2. 编译(compilation)

        编译的作用就是把预处理完的文件进行一系列语法分析及优化后生成相应的汇编文件。

        终端输入:

gcc -S reverse.i -o reverse.s
        运行完后会生成一个 reverse.s 文件:

UBuntu12.04下用gcc编译c文件过程详解

        用vim打开后可以看到一共变成了129行,并且没有了源文件的内容,变成了一条条汇编指令。

UBuntu12.04下用gcc编译c文件过程详解

   3. 汇编(Assembly)

        汇编就是把生成的汇编指令逐条翻译成机器可以识别的形式,即机器码,这一步会产生平台相关性,即决定了在哪种平台下运行。

        在终端输入:

gcc -c reverse.s -o reverse.o
        可以看到又生成了一个文件reverse.o。

UBuntu12.04下用gcc编译c文件过程详解

        是不是很熟悉,刚才第二种一步式就是生成它就可以直接运行了,现在就不行了!此时生成的文件为可重定位文件,还需要经过最后一步分链接才能变成可执行文件!此时用了但还有最后一步才能生成可执行文件,reverse.o打开之后是乱码,改成十六进制之后虽然能看清楚是什么数字,但毕竟是二进制,还要进行翻译才能形成汇编指令。可以用vim进行转换。在vim的命令行模式(进入后按Esc后按:进入命令行模式),输入:

vim -b filename //文件名,注意替换
//进入命令行后:
:%!xxd //要再输入一个:,一共两个:!
        如图所示:仅仅比汇编指令多了13行(包括过滤掉了6行)
UBuntu12.04下用gcc编译c文件过程详解

    4. 链接(Linking)

        这是最后一步,将生成的目标文件和其所依赖的库文件进行连接,生成一个可执行文件。链接的细节方面可以参考CSAPP的第七章,很详细,包括可执行目标文件和重定位目标文件的区别等。

        终端输入:

gcc reverse.o -o reverse
./reverse
        可以看到reverse可执行文件(菱形)就出来了,通过第二行命令就可以运行了。

UBuntu12.04下用gcc编译c文件过程详解

        运行结果与上面一步式相同,就不再列举了。到此就是整个gcc搞定C文件的全部步骤了。接下来就是gdb的调试了。