在Linux系统下,任意目录内创建一个简单的C程序,命名为hello.c,其代码如下:
1 #include
2 int main(){
3 //这里有个注释
4 printf("Hello Word\n");
5 return 0;
6 }
编译代码,生成可执行文件 a.out:
XXXX@ubuntu:~/hello$ gcc hello.c
XXXX@ubuntu:~/hello$ ls
a.out hello.c
运行可执行文件a.out ,生成结果:
XXXX@ubuntu:~/hello$ ./a.out
Hello Word
以上是一个程序最简单、最快捷的编译运行方式,但是在实际上,程序从代码到机器可执行的过程中,涉及预处理、编译、汇编、链接及运行等过程,了解这些过程是十分有必要的。
对上面的程序hello.c进行预处理过程,通常会进行以下操作:
1、删除程序里的注释内容;
2、把头文件的内容复制到预处理指令位置。
对==.c==文件的预处理,可以采用下述方法:
XXXX@ubuntu:~/hello$ gcc -E hello.c -o hello.i
XXXX@ubuntu:~/hello$ ls
hello.c hello.i
说明:
1、gcc -E filename.c 表示对一个.c文件进行预处理,E必须大写
2、gcc -E filename.c -o filename.i 表示把预处理文件命名为filename.i,此处的 -o 必须小写
3、预处理文件用 filename.i来表示。
1 # 1 ""
2 # 1 ""
3 # 1 "/usr/include/stdc-predef.h" 1 3 4
4 # 1 "" 2
5 # 1 "hello.c"
6 # 1 "/usr/include/stdio.h" 1 3 4
7 # 27 "/usr/include/stdio.h" 3 4
8 # 1 "/usr/include/features.h" 1 3 4
9 # 367 "/usr/include/features.h" 3 4
10 # 1 "/usr/include/i386-linux-gnu/sys/cdefs.h" 1 3 4
11 # 410 "/usr/include/i386-linux-gnu/sys/cdefs.h" 3 4
12 # 1 "/usr/include/i386-linux-gnu/bits/wordsize.h" 1 3 4
13 # 411 "/usr/include/i386-linux-gnu/sys/cdefs.h" 2 3 4
14 # 368 "/usr/include/features.h" 2 3 4
15 # 391 "/usr/include/features.h" 3 4
16 # 1 "/usr/include/i386-linux-gnu/gnu/stubs.h" 1 3 4
17
18
19
……
855
856
857
858 # 3 "hello.c"
859 int main(){
860
861 printf("Hello Word\n");
862 return 0;
863 }
上述代码段中,行号1~858所代表的代码即是 ==#include
预处理过程只是对文件的一个预处理,并没有进行语法的检查等。而且此时代码还只是C语言,需要先转换成汇编语言,这样的过程叫做编译。
XXXX@ubuntu:~/hello$ gcc -S hello.i -o hello.s
XXXX@ubuntu:~/hello$ ls
hello.c hello.i hello.s
说明:
1、gcc -S filename.i 表示对一个.i文件进行编译,S必须大写
2、gcc -S filename.i -o filename.s 表示把编译后的文件命名为filename.s,此处的 -o 必须小写
3、编译后的文件用 filename.s来表示。
用vim指令打开hello.s文件
1 .file "hello.c"
2 .section .rodata
3 .LC0:
4 .string "Hello Word"
5 .text
6 .globl main
7 .type main, @function
8 main:
9 .LFB0:
10 .cfi_startproc
11 leal 4(%esp), %ecx
12 .cfi_def_cfa 1, 0
……
31 .cfi_def_cfa 4, 4
32 ret
33 .cfi_endproc
34 .LFE0:
35 .size main, .-main
36 .ident "GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.10) 5 .4.0 20160609"
37 .section .note.GNU-stack,"",@progbits
此时的文件已经被翻译成AT&T汇编语言文件。
接下来,进行汇编语言到机器语言的翻译,这个过程叫汇编,过程结束后,生成目标文件.o。
XXXX@ubuntu:~/hello$ gcc -c hello.s
XXXX@ubuntu:~/hello$ ls
hello.c hello.i hello.o hello.s
说明:
1、-c 中的c一定要小写,不需要再加-o进行命名
2、hello.o是目标文件,是机器语言编写成的,但是还不可以执行,缺少必要的运行时文件。
为了生成可执行文件,需要将运行时文件及目标文件进行绑定,这个过程即是链接,采用如下指令:
XXXX@ubuntu:~/hello$ gcc hello.o
XXXX@ubuntu:~/hello$ ls
a.out hello.c hello.i hello.o hello.s
此时 a.out可执行文件生成。
运行可执行文件:
XXXX@ubuntu:~/hello$ ./a.out
Hello Word
此时,输出结果Hello Word。