编译的4个过程
- 预处理
- 编译
- 汇编
- 链接
其中gcc编译器除了可以编译C语言也可以编译C++,只是一般用g++编译方便一点。
#include <stdio.h>
int main()
{
printf("hello world\n");
return 0;
}
保存为hello.c
预处理
gcc -E hello.c -o hello.i
- #define宏定义的展开
- 处理条件编译#if, #ifdef等
- #include头文件展开
825 extern char *ctermid (char *__s) __attribute__ ((__nothrow__ , __leaf__));
826 # 913 "/usr/include/stdio.h" 3 4
827 extern void flockfile (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__));
828
829
830
831 extern int ftrylockfile (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__)) ;
832
833
834 extern void funlockfile (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__));
835 # 943 "/usr/include/stdio.h" 3 4
836
837 # 2 "hello.c" 2
838 int main()
839 {
840 printf("hello world\n");
841 return 0;
842 }
编译
gcc -S hello.i -o hello.s
词法分析,语义分析。
1 .file "hello.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 movl $.LC0, %edi
17 call puts
18 movl $0, %eax
19 popq %rbp
20 .cfi_def_cfa 7, 8
21 ret
22 .cfi_endproc
23 .LFE0:
24 .size main, .-main
25 .ident "GCC: (GNU) 4.8.5 20150623 (Red Hat 4.8.5-44)"
26 .section .note.GNU-stack,"",@progbits
汇编
gcc -c hello.s -o hello.o
将汇编代码转成机器码。也可以直接编译源文件gcc -c hello.cpp
[root@VM-0-12-centos code]# hexdump hello.o
0000000 457f 464c 0102 0001 0000 0000 0000 0000
0000010 0001 003e 0001 0000 0000 0000 0000 0000
0000020 0000 0000 0000 0000 0298 0000 0000 0000
0000030 0000 0000 0040 0000 0000 0040 000d 000c
0000040 4855 e589 00bf 0000 e800 0000 0000 00b8
0000050 0000 5d00 68c3 6c65 6f6c 7720 726f 646c
0000060 0000 4347 3a43 2820 4e47 2955 3420 382e
-c可以一次编译多个文件,会生成多个.o文件,此时不可以指定-o 文件名称。
链接
gcc hello.o -o hello 生成可执行文件。
如果有多个文件,则使用gcc a.o b.o c.o -o result
将多个文件的目标链接,比如printf在别的文件,需要将当前文件和printf所在的文件进行关联,这个过程叫做链接。
一次编译到位
gcc hello.c可以直接自动执行编译的各个阶段,并生成一个a.out的文件。也可以指定生成的可执行文件名称gcc hello.c helloworld
gcc编译C++
hello.c
#include <stdio.h>
int main()
{
bool isEven = false;
return 1;
}
由于c语言没有bool类型,属于C++标准,因此不能使用gcc hello.c编译。可以指定指定编译的语言,此时,将不根据文件名称的后缀识别。
gcc -x c++ hello.c可以正常编译,其中-x表示告诉编译器源代码的编程语言,可以使用的语言有c,objective-c,c-header,c++,cpp-output,assembler,assembler-with-cpp。
或者直接将文件名称改成hello.cpp,这就可以使用gcc hello.cpp直接编译C++代码。
#include <iostream>
using namespace std;
int main()
{
cout << "Hello world"<<endl;
return 1;
}
由于cout是C++标准的内容,因此得使用gcc hello.cpp -lstdc++进行编译。-l表示链接C++标准库。
其他编译参数
选项-I(大写的i)
可以用来指定头文件搜索路径。
使用尖括号的包含头文件
- 1
-I指定的路径 - 2 在
/usr/lcoal/include搜索 - 3 在
/usr/include搜索
在/root/code创建hello.cpp
#include <stdio.h>
#include <MyInclude.h>
int main()
{
printf("value0 %s\n ",IncludeValue0);
return 1;
}
// /root/MyInclude.h
#define IncludeValue0 "/root/MyInclude IncludeValue0"
使用gcc hello.cpp -I /root可以编译通过。
为了验证顺序,生成如下文件。
[root@VM-0-12-centos code]# cat /usr/include/MyInclude.h
#define IncludeValue0 "/usr/include/MyInclude IncludeValue0"
[root@VM-0-12-centos code]# cat /usr/local/include/MyInclude.h
#define IncludeValue0 "/root/local/include/MyInclude IncludeValue0
使用指定的-I路径
[root@VM-0-12-centos code]# gcc hello.cpp -I /root
[root@VM-0-12-centos code]# ./a.out
value0 /root/MyInclude IncludeValue0
-I 找不到
[root@VM-0-12-centos code]# rm /root/MyInclude.h
rm: remove regular file ‘/root/MyInclude.h’? y
[root@VM-0-12-centos code]# gcc hello.cpp -I /root
[root@VM-0-12-centos code]# ./a.out
value0 /root/local/include/MyInclude IncludeValue0
/usr/local/include找不到
[root@VM-0-12-centos code]# rm /usr/local/include/MyInclude.h
rm: remove regular file ‘/usr/local/include/MyInclude.h’? y
[root@VM-0-12-centos code]# gcc hello.cpp -I /root
[root@VM-0-12-centos code]# ./a.out
value0 /usr/include/MyInclude IncludeValue0
[root@VM-0-12-centos code]#
/usr/include 找不到,编译报错
[root@VM-0-12-centos code]# rm /usr/include/MyInclude.h
rm: remove regular file ‘/usr/include/MyInclude.h’? y
[root@VM-0-12-centos code]# gcc hello.cpp -I /root
hello.cpp:2:23: fatal error: MyInclude.h: No such file or directory
#include <MyInclude.h>
^
compilation terminated.
使用双引号的包含头文件
- 1 先在当前工作目录
- 2
-I指定的目录 - 3
/usr/lcoal/include - 4
/usr/include
-include包含头文件
[root@VM-0-12-centos code]# gcc hello.cpp -include /root/test.cpp
[root@VM-0-12-centos code]# ./a.out
hello
[root@VM-0-12-centos code]# cat hello.cpp
#include <stdio.h>
int main()
{
printf("%s\n ",HI);
return 0;
}
[root@VM-0-12-centos code]# cat /root/test.cpp
#define HI "hello"
-Wall 显示警告信息
[root@VM-0-12-centos code]# gcc hello.cpp
[root@VM-0-12-centos code]# ./a.out
a = 0
[root@VM-0-12-centos code]# gcc hello.cpp -Wall
hello.cpp: In function ‘int main()’:
hello.cpp:5:24: warning: ‘a’ is used uninitialized in this function [-Wuninitialized]
printf("a = %d\n ", a);
^
[root@VM-0-12-centos code]# ./a.out
a = 0
-g生成可调试的信息
gcc hello.cpp -g可以生成调试信息,供gdb调试用。