从代码到可执行程序的四个阶段:
预处理-->编译-->汇编-->链接
一步完成从代码到可执行程序:
对c程序来说使用
gcc name.c -o name.exe
执行命令后会生成可执行文件 name.exe。
对c++程序来使用
g++ name.cpp -o name.exe
执行命令后生成可执行文件name.exe。
gcc和g++的区别:
对C程序来说,gcc使用c代码的方式编译 ,而g++则使用C++代码的方式编译。注意:使用C++的方式编译C代码可能会出错。
对C++程序来说,两者没有差别。
四个阶段完成从代码到可执行程序:
源文件b.cpp代码如下:
#include<iostream> using namespace std; /* 这是一个注释! */ int main() { cout<<"c++ program!"<<endl; system("pause"); return 0; }
1、预处理
g++ -E(大写) name.cpp
-E 选项用来对原代码做预处理操作。使用 g++ -E b.cpp命令后,只会将预处理指操作的结果输出到屏幕,若想保存操作结果则要搭配-o使用。
预处理主要处理源文件和头文件中以#开头的命令(#<iostream>等),并删除程序中的注释信息等。
运行 g++ -E b.cpp -o b.i 会生成一个b.i文件
打开b.i文件后可以看到一些信息,发现其中注释已经被删掉了,头文件被替换为好多行代码。
# 1 "b.cpp" # 1 "<built-in>" # 1 "<command-line>" # 1 "b.cpp" # 1 "C:/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/iostream" 1 3 # 36 "C:/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/iostream" 3 # 37 "C:/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/iostream" 3 # 1 "C:/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/x86_64-w64-mingw32/bits/c++config.h" 1 3 # 236 "C:/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/x86_64-w64-mingw32/bits/c++config.h" 3 # 236 "C:/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/x86_64-w64-mingw32/bits/c++config.h" 3 namespace std { typedef long long unsigned int size_t; typedef long long int ptrdiff_t; typedef decltype(nullptr) nullptr_t; ..... ..... ..... ..... ..... extern istream cin; extern ostream cout; extern ostream cerr; extern ostream clog; extern wistream wcin; extern wostream wcout; extern wostream wcerr; extern wostream wclog; static ios_base::Init __ioinit; } # 2 "b.cpp" 2 # 3 "b.cpp" using namespace std; int main() { cout<<"c++ program!"<<endl; system("pause"); return 0; }
2、编译
g++ -S(大写) name.cpp / name.i
使用该g++ -S b.cpp 后会自动生成b.s汇编代码文件,将c++代码翻译为汇编代码。
g++ -S指令并非必须经过预处理后的.i文件,-S选项的功能是令GCC编译器将指定文件预处理至编译阶段结束。
也就是说g++ -S可以处理.i文件,也可以处理原代码文件。
.file "b.cpp" .text .section .rdata,"dr" _ZStL19piecewise_construct: .space 1 .lcomm _ZStL8__ioinit,1,1 .def __main; .scl 2; .type 32; .endef .LC0: .ascii "c++ program! " .LC1: .ascii "pause " .text .globl main .def main; .scl 2; .type 32; .endef .seh_proc main main: .LFB1573: pushq %rbp .seh_pushreg %rbp movq %rsp, %rbp .seh_setframe %rbp, 0 subq $32, %rsp .seh_stackalloc 32 .seh_endprologue call __main leaq .LC0(%rip), %rdx movq .refptr._ZSt4cout(%rip), %rcx call _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc movq .refptr._ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_(%rip), %rdx movq %rax, %rcx call _ZNSolsEPFRSoS_E leaq .LC1(%rip), %rcx call system movl $0, %eax addq $32, %rsp popq %rbp ret .seh_endproc .def __tcf_0; .scl 3; .type 32; .endef .seh_proc __tcf_0 __tcf_0: .LFB2063: pushq %rbp .seh_pushreg %rbp movq %rsp, %rbp .seh_setframe %rbp, 0 subq $32, %rsp .seh_stackalloc 32 .seh_endprologue leaq _ZStL8__ioinit(%rip), %rcx call _ZNSt8ios_base4InitD1Ev nop addq $32, %rsp popq %rbp ret .seh_endproc .def _Z41__static_initialization_and_destruction_0ii; .scl 3; .type 32; .endef .seh_proc _Z41__static_initialization_and_destruction_0ii _Z41__static_initialization_and_destruction_0ii: .LFB2062: pushq %rbp .seh_pushreg %rbp movq %rsp, %rbp .seh_setframe %rbp, 0 subq $32, %rsp .seh_stackalloc 32 .seh_endprologue movl %ecx, 16(%rbp) movl %edx, 24(%rbp) cmpl $1, 16(%rbp) jne .L6 cmpl $65535, 24(%rbp) jne .L6 leaq _ZStL8__ioinit(%rip), %rcx call _ZNSt8ios_base4InitC1Ev leaq __tcf_0(%rip), %rcx call atexit .L6: nop addq $32, %rsp popq %rbp ret .seh_endproc .def _GLOBAL__sub_I_main; .scl 3; .type 32; .endef .seh_proc _GLOBAL__sub_I_main _GLOBAL__sub_I_main: .LFB2064: pushq %rbp .seh_pushreg %rbp movq %rsp, %rbp .seh_setframe %rbp, 0 subq $32, %rsp .seh_stackalloc 32 .seh_endprologue movl $65535, %edx movl $1, %ecx call _Z41__static_initialization_and_destruction_0ii nop addq $32, %rsp popq %rbp ret .seh_endproc .section .ctors,"w" .align 8 .quad _GLOBAL__sub_I_main .ident "GCC: (x86_64-posix-seh-rev0, Built by MinGW-W64 project) 8.1.0" .def _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc; .scl 2; .type 32; .endef .def _ZNSolsEPFRSoS_E; .scl 2; .type 32; .endef .def system; .scl 2; .type 32; .endef .def _ZNSt8ios_base4InitD1Ev; .scl 2; .type 32; .endef .def _ZNSt8ios_base4InitC1Ev; .scl 2; .type 32; .endef .def atexit; .scl 2; .type 32; .endef .section .rdata$.refptr._ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_, "dr" .globl .refptr._ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_ .linkonce discard .refptr._ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_: .quad _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_ .section .rdata$.refptr._ZSt4cout, "dr" .globl .refptr._ZSt4cout .linkonce discard .refptr._ZSt4cout: .quad _ZSt4cout
3、汇编
g++ -c name.cpp / name.s
使用g++ -c b.s对汇编代码进行汇编会生成相应的目标文件(b.o文件)
目标文件为二进制文件,由于尚未经过链接操作,所以无法直接运行。
4、链接
g++ b.o -o b.exe
将得到的b.o文件经过链接(一些函数和全局变量等)后便得到了可执行程序。
并不需要在g++添加任何选项,g++会在b.o的基础上完成链接操作。
参考链接:http://c.biancheng.net/view/7960.html