C++从代码到可执行文件的四个阶段

 从代码到可执行程序的四个阶段:

预处理-->编译-->汇编-->链接

  

一步完成从代码到可执行程序:

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!\0"
.LC1:
    .ascii "pause\0"
    .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

 

 

 

 

posted @ 2020-08-17 08:39  夏~  阅读(2158)  评论(0编辑  收藏  举报