C语言编译过程总结

        开发C程序有四个步骤:预处理、编译、汇编和链接。任何一个体系结构处理器上都可以使用C语言程序,只要该体系结构处理器有相应的C语言编译器和库,那么C源代码就可以编译并连接到目标二进制文件上运行。

我们创建一个test.c为例来讲解程序编译的过程

test.c:

#include <stdio.h>

int add(int a, int b)
{
    return a+b;
}
int sub(int a, int b)
{
    return a-b;
}

int main()
{
    int a = 88;
    int b = 66;

    int sum = add(a, b); 
    printf("a=%d, b=%d, a+b=%d\n", a, b, sum);

    int dif = sub(a, b); 
    printf("a=%d, b=%d, a-b=%d\n", a, b, dif);
}

一:预处理

        使用预处理器把源文件test.c经过预处理生成test.i文件,预处理用于将所有的#include头文件以及宏定义替换成其真正的内容。预处理主要工作如下:

  • 处理所有的注释,以空格代替
  • 将所有的 #define 删除,并且展开所有的宏定义
  • 处理条件编译指令 #if, #ifdef, #elif,#else,#endif
  • 处理 #include,展开被包含的文件
  • 保留编译器需要使用的 #pragma 指令

预编译命令:

gcc -E test.c -o test.i

        上述命令中-E是让编译器在预处理之后就退出,不进行后续编译过程;-o是指定输出文件名。预处理之后得到的仍然是文本文件。-I指定头文件目录,这里指定的是我们自定义的头文件目录。

        test.i文件的部分截图如下:

二:编译

对预处理文件进行词法分析,语法分析和语义分析

  • 词法分析:分析关键字,标示符,立即数等是否合法
  • 语法分析:分析表达式是否遵循语法规则
  • 语义分析:在语法分析的基础上进一步分析表达式是否合法

分析结束后进行代码优化生成相应的汇编代码文件

编译命令:

gcc -S test.c -o test.s

生成的汇编文件如下:

[root@localhost testEg]# cat test.s
        .file   "test.c"
        .text
        .globl  add
        .type   add, @function
add:
.LFB0:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register 6
        movl    %edi, -4(%rbp)
        movl    %esi, -8(%rbp)
        movl    -8(%rbp), %eax
        movl    -4(%rbp), %edx
        addl    %edx, %eax
        popq    %rbp
        .cfi_def_cfa 7, 8
        ret
        .cfi_endproc
.LFE0:
        .size   add, .-add
        .globl  sub
        .type   sub, @function
sub:
.LFB1:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register 6
        movl    %edi, -4(%rbp)
        movl    %esi, -8(%rbp)
        movl    -8(%rbp), %eax
        movl    -4(%rbp), %edx
        subl    %eax, %edx
        movl    %edx, %eax
        popq    %rbp
        .cfi_def_cfa 7, 8
        ret
        .cfi_endproc
.LFE1:
        .size   sub, .-sub
        .section        .rodata
.LC0:
        .string "a=%d, b=%d, a+b=%d\n"
.LC1:
        .string "a=%d, b=%d, a-b=%d\n"
        .text
        .globl  main
        .type   main, @function
main:
.LFB2:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register 6
        subq    $16, %rsp
        movl    $88, -4(%rbp)
        movl    $66, -8(%rbp)
        movl    -8(%rbp), %edx
        movl    -4(%rbp), %eax
        movl    %edx, %esi
        movl    %eax, %edi
        call    add
        movl    %eax, -12(%rbp)
        movl    -12(%rbp), %ecx
        movl    -8(%rbp), %edx
        movl    -4(%rbp), %eax
        movl    %eax, %esi
        movl    $.LC0, %edi
        movl    $0, %eax
        call    printf
        movl    -8(%rbp), %edx
        movl    -4(%rbp), %eax
        movl    %edx, %esi
        movl    %eax, %edi
        call    sub
        movl    %eax, -16(%rbp)
        movl    -16(%rbp), %ecx
        movl    -8(%rbp), %edx
        movl    -4(%rbp), %eax
        movl    %eax, %esi
        movl    $.LC1, %edi
        movl    $0, %eax
        call    printf
        leave
        .cfi_def_cfa 7, 8
        ret
        .cfi_endproc
.LFE2:
        .size   main, .-main
        .ident  "GCC: (GNU) 4.8.5 20150623 (Red Hat 4.8.5-44)"
        .section        .note.GNU-stack,"",@progbits

三:汇编

  • 汇编器将汇编代码转变为机器的可以执行指令
  • 每条汇编语句几乎都对应一条机器指令

 这一步产生的文件叫做目标文件,是二进制格式

gcc汇编过程通过as命令完成:

as test.s -o test.o

 等价于:

gcc -c test.s -o test.o

四:链接

        链接过程使用链接器将该目标文件与其他目标文件、库文件、启动文件等链接起来生成可执行文件。

链接命令如下:

gcc test.o -o test

最后运行生成的可执行文件:

[root@localhost testEg]# ./test
a=88, b=66, a+b=154
a=88, b=66, a-b=22

总结:

编译过程分为预处理,编译,汇编和链接四个阶段

  • 预处理:处理注释,宏以及已经以 # 开头的符号
  • 编译:进行词法分析,语法分析和语义分析等
  • 汇编:将汇编代码翻译为机器指令的目标文件
  • 链接:链接到一起生成可执行程序

常用编译命令选项

假设源程序文件名为test.c。

1. 无选项编译链接
用法:#gcc test.c
作用:将test.c预处理、汇编、编译并链接形成可执行文件。这里未指定输出文件,默认输出为a.out。

2. 选项 -o
用法:#gcc test.c -o test
作用:将test.c预处理、汇编、编译并链接形成可执行文件test。-o选项用来指定输出文件的文件名。

3. 选项 -E
用法:#gcc -E test.c -o test.i
作用:将test.c预处理输出test.i文件。

4. 选项 -S
用法:#gcc -S test.i 
作用:将预处理输出文件test.i汇编成test.s文件。

5. 选项 -c
用法:#gcc -c test.s
作用:将汇编输出文件test.s编译输出test.o文件。

6. 无选项链接
用法:#gcc test.o -o test
作用:将编译输出文件test.o链接成最终可执行文件test。

7. 选项-O
用法:#gcc -O1 test.c -o test
作用:使用编译优化级别1编译程序。级别为1~3,级别越大优化效果越好,但编译时间越长。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
C语言编译过程是将C语言源代码转化为可以在计算机上执行的可执行文件的过程。这个过程包括了预处理、编译、汇编和链接四个主要步骤。 首先是预处理阶段,预处理器负责对源代码进行处理,将所有的宏定义、条件编译指令、头文件包含等处理为实际的C代码。预处理器会将处理后的文件保存为.i文件。 接下来是编译阶段,编译器会将预处理后的代码翻译成汇编代码,该代码使用一种特定的汇编语言表示。编译器会对代码进行语法检查、语义分析、优化等处理,并生成汇编代码。编译器将处理后的代码保存为.s文件。 然后是汇编阶段,在这个阶段,汇编器将汇编代码转化为机器码指令,这些指令可以被计算机直接执行。汇编器将处理后的代码保存为.o文件。 最后是链接阶段,链接器将多个目标文件(.o文件)和库文件进行合并,生成最终的可执行文件。链接器会解析并处理数据和函数引用,将它们与实际的定义进行链接。同时,链接器还会进行地址重定位、符号解析等操作,确保连接的正确性和可执行文件的完整性。 总结起来,C语言编译过程包括预处理、编译、汇编和链接四个步骤,分别将源代码转化为预处理后的代码、汇编代码和机器码,并最终生成可执行文件。每个阶段都有特定的处理任务和输出文件,形成了完整的编译过程

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ftzchina

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值