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 资源档编译器 |