加入收藏 | 设为首页 | 会员中心 | 我要投稿 我爱故事小小网_铜陵站长网 (http://www.0562zz.com/)- 视频终端、云渲染、应用安全、数据安全、安全管理!
当前位置: 首页 > 教程 > 正文

C代码编译成可执行程序的步骤

发布时间:2021-12-09 18:17:11 所属栏目:教程 来源:互联网
导读:C代码通过编译器编译成可执行代码,经历了四个阶段,依次为:预处理、编译、汇编、链接。 接下来详细讲解各个阶段 一、预处理 1、任务:进行宏定义展开、头文件展开、条件编译,不检查语法。 2、命令:gcc -E [源文件] -o [预处理文件] 3、案例:用gcc编译器

C代码通过编译器编译成可执行代码,经历了四个阶段,依次为:预处理、编译、汇编、链接。
接下来详细讲解各个阶段
 
一、预处理
1、任务:进行宏定义展开、头文件展开、条件编译,不检查语法。
 
2、命令:gcc -E [源文件]  -o [预处理文件]
 
3、案例:用gcc编译器预处理demo1.c代码,预处理后的文本放到demo1.i中。(gcc -E demo1.c -o demo1.i)
 
demo1.c代码如下:
 
 1 #include <stdio.h>
 2
 3 #define add(a, b) (a + b)
 4 #define sub(a, b) (a - b)
 5
 6 int main(void)
 7 {
 8     int a, b, c, d;
 9 #ifndef __cplusplus
10     a = b = c = d = 1;
11 #else
12     a = b = c = d = 2;
13 #endif
14     printf("num = %dn", sub(add(a, b), add(c, d)));
15     return 0;
16 }
生成的demo1.i代码如下:
 
 1 # 1 "demo.c"
 2 # 1 "<command-line>"
 3 # 1 "/usr/include/stdc-predef.h" 1 3 4
 4 # 1 "<command-line>" 2
 5
 6 此处省略800行...
 7
 8 extern void funlockfile (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__));
 9 # 943 "/usr/include/stdio.h" 3 4
10
11 # 2 "demo.c" 2
12
13
14 int main(void)
15 {
16     int a, b, c, d;
17
18     a = b = c = d = 1;
19
20
21
22     printf("num = %dn", ((a + b) - (c + d)));
23     return 0;
24 }
通过案例可以发现:#define宏定义、stdio.h头文件、#ifdef条件编译都被替换了,并且你还可以故意写一句有语法错误的代码,但是却不会报错。由于stdio.h头文件长达800多行,因此在demo1.i中只截取开头和结尾的几行。 
 
二、编译
1、任务:检查语法,将预处理过的文件编译生成汇编文件。
 
2、命令:gcc -S [源文件] -o [汇编文件]
 
3、案例;用gcc编译器编译demo2.c代码,编译后的汇编代码放到demo2.s中。(gcc -S demo2.c  -o demo2.s)
 
demo2.c代码如下:
 
1 #include <stdio.h>
2
3 int main(int argc, char *argv[])
4 {
5     printf("hello worldn");
6     return 0;
7 }
生成的demo2.s代码如下:
 
 1     .file    "demo2.c"
 2     .section    .rodata
 3 .LC0:
 4     .string    "hello world"
 5     .text
 6     .globl    main
 7     .type    main, @function
 8 main:
 9 .LFB0:
10     .cfi_startproc
11     pushq    %rbp
12     .cfi_def_cfa_offset 16
13     .cfi_offset 6, -16
14     movq    %rsp, %rbp
15     .cfi_def_cfa_register 6
16     subq    $16, %rsp
17     movl    %edi, -4(%rbp)
18     movq    %rsi, -16(%rbp)
19     movl    $.LC0, %edi
20     call    puts
21     movl    $0, %eax
22     leave
23     .cfi_def_cfa 7, 8
24     ret
25     .cfi_endproc
26 .LFE0:
27     .size    main, .-main
28     .ident    "GCC: (Ubuntu 4.8.2-19ubuntu1) 4.8.2"
29     .section    .note.GNU-stack,"",@progbits
通过案例可以看出,我们写的c代码被编译成了汇编代码。故意写错一个语法点,编译器将报错。
 
三、汇编
1、任务:将汇编文件生成目标文件(2进制文件)。
 
2、命令:gcc -s [源文件] -o [目标文件]
 
3、案例:用gcc编译器汇编demo3.c代码,编译后的二进制代码放到demo3.o中。(gcc -c demo3.c  -o demo3.o)
 
demo3.c代码如下:
 
1 #include <stdio.h>
2
3 int main(int argc, char *argv[])
4 {
5     printf("hello worldn");
6     return 0;
7 }
生成的demo3.o代码如下:
 
 
 
通过汇编阶段,文本代码变成了二进制代码,也就是计算机可以识别的代码。c语言中,二进制代码文件是以.o为后缀名的。
 
四、链接
1、任务:找到依赖的库文件,将目标文件链接为可执行程序。
 
2、命令:gcc -c [目标文件] -o [可执行程序] -l[动态库名]
 
3、案例:通过gcc编译器让demo4链接自己制作的libadd.so动态库,并把demo4编译成可执行程序。gcc demo4.c -o demo4 -L./ -ladd
 
demo4.c代码如下:
 
 
 
1 #include <stdio.h>
2 #include "add.h"
3
4 int main(int argc, char *argv[])
5 {
6     printf("add = %dn", add(1, 1));
7     return 0;
8 }
通过file命令查看可执行程序的信息:
 
 
 
运行结果:add = 2
 
还可以通过“size [可执行程序]”命令,来查看程序的text段、data段、bss段的大小。

(编辑:我爱故事小小网_铜陵站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    热点阅读