g++使用
1. 编译过程
- 预处理(-E)
- 编译(-S)
- 汇编(-c)
- 链接(-O)
1.1 预处理(-E)
为了直观的了解预处理,理解预处理做了哪些工作,不说那么多,直接上代码,创建main.h与main.cpp文件,有头文件引用,有宏定义,有注释,还有未定义参数赋值的错误。代码如下:
/* main.h */ #define VALUES 100 int test(); void test2(){} void test3(){} void test4(){} /* main.cpp */ #include <main.h> int main() { // 参数未定义 a = 100; return test(); } int test() { return VALUES; } 预处理:
g++ -E main.cpp -I. > main.i
main.i为:
# 1 "main.cpp" # 1 "<built-in>" # 1 "<command-line>" # 1 "/usr/include/stdc-predef.h" 1 3 4 # 1 "<command-line>" 2 # 1 "main.cpp" # 1 "./main.h" 1 int test(); void test2(){} void test3(){} void test4(){} # 2 "main.cpp" 2 int main() { a = 100; return test(); } int test() { return 100; } 生成很顺利,可以看出,预处理工作:
- 不关注语法错误
- 宏替换
- 消除注释
- 将头文件整个包括进来,连空行都是完整的复制过来的
1.2 编译(-S)
编译将会把预处理生成的.i文件生成为.s的汇编代码文件。
继续上面的代码,当我们尝试编译上面生成的main.i文件时,会提示语法错误:
g++ -S main.i
main.cpp: In function ‘int main()’: main.cpp:6:5: error: ‘a’ was not declared in this scope a = 100;
我们在main.c中加入int a;
g++ -E main.cpp -I. > main.i g++ -S main.i
这样就可以通过编译,默认生成main.s汇编文件,打开如下:
.file "main.cpp" .text .globl _Z5test2v .type _Z5test2v, @function _Z5test2v: .LFB0: .cfi_startproc pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset 6, -16 movq %rsp, %rbp .cfi_def_cfa_register 6 nop popq %rbp .cfi_def_cfa 7, 8 ret .cfi_endproc .LFE0: .size _Z5test2v, .-_Z5test2v .globl _Z5test3v .type _Z5test3v, @function _Z5test3v: .LFB1: .cfi_startproc pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset 6, -16 movq %rsp, %rbp .cfi_def_cfa_register 6 nop popq %rbp .cfi_def_cfa 7, 8 ret .cfi_endproc .LFE1: .size _Z5test3v, .-_Z5test3v .globl _Z5test4v .type _Z5test4v, @function _Z5test4v: .LFB2: .cfi_startproc pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset 6, -16 movq %rsp, %rbp .cfi_def_cfa_register 6 nop popq %rbp .cfi_def_cfa 7, 8 ret .cfi_endproc .LFE2: .size _Z5test4v, .-_Z5test4v .globl main .type main, @function main: .LFB3: .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 $100, -4(%rbp) call _Z4testv leave .cfi_def_cfa 7, 8 ret .cfi_endproc .LFE3: .size main, .-main .globl _Z4testv .type _Z4testv, @function _Z4testv: .LFB4: .cfi_startproc pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset 6, -16 movq %rsp, %rbp .cfi_def_cfa_register 6 movl $100, %eax popq %rbp .cfi_def_cfa 7, 8 ret .cfi_endproc .LFE4: .size _Z4testv, .-_Z4testv .ident "GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.11) 5.4.0 20160609" .section .note.GNU-stack,"",@progbits
从这开始就和汇编是一样的了,再深入就需要去了解汇编的原理,后面两个过程不再详细描述。
1.3 汇编(-c)
汇编的工作是将汇编代码转成机器代码,注意“-c”是小写字母,而预处理和编译都是大写字母。汇编后生成.o目标文件。
g++ -c main.i
生成main.o
1.4 链接(-o)
将.o、.a、.so等文件链接生成可执行文件。
g++ main.o -o main
生成main可执行文件
g++ main.o
生成默认的a.out可执行文件