c++编译知识

1、 编译介绍

C++语言编译主要分为四个阶段:
源代码:

  #include <stdio.h>
  #include <assert.h>
  
  #define paster( n ) printf( "token " #n" = %d\n ", token##n ) 
  int add(int a, int b);
  int main()
  {
      assert(0);
      int n = 9;
      int token9 = 10;
      paster(9);
      return 0;
  }

1、1 预处理阶段

此阶段主要完成#符号后面的各项内容到源文件的替换,往往一些莫名其妙的错误都是出现在头文件中的,要在工程中注意积累一些错误知识, 此阶段产生[.i]文件。

  • #ifdef等内容,完成条件编译内容的替换
  • #include中内容,在当前目录或者指定目录,或者默认目录搜索头文件,并将头文件拷贝到源文件中。
  • #define的内容,替换define的内容(包括上一步的头文件中的define内容)

注:

  • ##是一个连接符号,用于把参数连在一起
  • #是“字符串化”的意思。出现在宏定义中的#是把跟在后面的参数转换成一个字符串
    示例:
#define paster( n ) printf( "token " #n" = %d\n ", token##n ) 

所以paster(9);就是相当于 printf("token 9 = %d\n",token9);
注: :-E 为预编译 选项

g++ -E test.cpp -o test.i

查看预编译后的文件:

976 # 3 "test.cpp" 2
977 
978 
979 int add(int a, int b);
980 int main()
981 {
982     ((0) ? static_cast<void> (0) : __assert_fail ("0", "test.cpp", 8, __PRETTY_FUNCTION__));
983     int n = 9;
984     int token9 = 10;
985     printf( "token " "9"" = %d\n ", token9 );
986     return 0;
987 }

1、2 编译阶段

此阶段完成语法和语义分析,然后生成中间代码,此中间代码是汇编代码,但是还不可执行,gcc编译的中间文件是[.s]文件。

在此阶段会出现各种语法和语义错误,特别要小心未定义的行为,这往往是致命的错误。

第一个阶段和第二个阶段由编译器完成。
使用:注: -S 为编译选项
命令如下:

 g++ -S test.i  -o test.s

也可以直接生成 .s文件,命令如下:

g++ -S test.cpp -o test.s

查看生成的test.s 文件

        .file   "test.cpp"
        .section        .rodata
.LC0:
        .string "test.cpp"
.LC1:
        .string "0"
        .text
        .file   "test.cpp"
        .section        .rodata
        .file   "test.cpp"
        .section        .rodata
.LC0:
        .string "test.cpp"
.LC1:
        .string "0"
        .text
.globl main
        .type   main, @function
main:
.LFB0:
        .cfi_startproc
        .cfi_personality 0x3,__gxx_personality_v0
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register 6
        subq    $16, %rsp
        movl    $_ZZ4mainE19__PRETTY_FUNCTION__, %ecx
        movl    $8, %edx
        movl    $.LC0, %esi
        movl    $.LC1, %edi
        call    __assert_fail
        .cfi_endproc
.LFE0:
        .size   main, .-main

1、3 汇编阶段

此阶段主要完成将汇编代码翻译成机器码指令,并将这些指令打包形成可重定位的目标文件,[.O]文件,是二进制文件。
c
此阶段由汇编器完成。
命令如下:注: -c 为汇编 选项

 g++ -c test.s -o test.o

g++ -c test.cpp -o test.o

1、4 链接阶段

此阶段完成文件中调用的各种函数跟静态库和动态库的连接,并将它们一起打包合并形成目标文件,即可执行文件。

此阶段由链接器完成。
命令如下:注: -c 为链接 选项

 g++ -o test test.cpp 

 g++ test.cpp -o test

或   

 g++ -o test test.o

使用nm -c test 可以查看可执行文件包含的函数;
linux nm和ldd解读

编译图解对应
编译图解对应

2、编译器介绍

编译器 说明
as 汇编器
ld 连接器
gprof 性能分析工具程序
addr2line 从目标文件的虚拟地址取得文件的行号或符号
ar 可以对静态库做创建、修改和取出的操作。
c++filt 解码 C++ 的符号
dlltool 创建 Windows 动态库
gold 另一种连接器
nlmconv 可以转换成 NetWare Loadable Module 目标文件格式
nm 显示目标文件内的符号
objcopy 复制目标文件,过程中可以修改
objdump 显示目标文件的相关信息,亦可反汇编
ranlib 产生静态库的索引
readelf 显示 ELF 文件的内容
size 列出总体和 section 的大小
strings 列出任何二进制档内的可显示字符串
strip 从目标文件中移除符号
windmc 产生 Windows 消息资源
windres Windows 资源档编译器
posted @ 2021-01-08 17:35  lihaihui199102  阅读(136)  评论(0编辑  收藏  举报