编译器
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了编译器相关的知识,希望对你有一定的参考价值。
绝大部分摘自《程序员的自我修养》一书,侵删。
对于平常的的开发,我们很少关注到编译和链接的过程,因为我们通常在IDE中进行开发,而IDE会把编译和链接合在一起一步完成,称为构建(build),就算我们使用命令行编译,也只用一行代码就能够完成非常复杂的过程,g++ hello.cpp 就能生成一个可供执行的exe文件。
而在平时的开发中,IDE提供的默认配置和强大功能掩盖了系统软件的运行机制,偶尔程序出现的莫名其妙的错误,我也只能被水淹没,不知所措。学一波编译器,希望能解决掉我exe运行不了的问题。。。
从源文件到可执行文件的操作分为四步:
1.预编译 (.c/.cpp--->.i/.ii)
2.编译 (.i/.ii--->.s)
3.汇编 (.s--->.o)
4.链接 (.o--->.out)
1.预编译
.c和.cpp或.cxx被预编译后分别会生成.i或.ii文件,相当于:
gcc -E hello.c -o hello.i
或者
gcc hello.c>hello.i
在c语言中存在许多以#开头的语句,这些语句叫做预编译指令,例如: #include #define #if 等,而预编译的作用就是将这些内容全部处理掉:
1. 删除所有的#define 并将宏定义展开
2. 处理所有的条件预编译指令,如#if #ifdef #eif #else #endif
3. 处理#include ,将被包含文件插入改预编译指令的位置。这个过程递归进行,也就是说被包含文件还可能包含其他文件
4. 删除所有注释
5. 添加行号和文件名标识比如#2 "hello.c" 2 以便于编译器产生调试用的行号信息,编译产生错误时能显示行号
6.保留所有的#pragma 编译器指令
我们可以通过查看预编译后的i文件来判断宏定义和头文件是否正确。
2.编译和汇编
编译器负责将你的高级语言转换为汇编语言,对预处理后的i文件进行词法分析、语法分析、语义分析、优化后生成汇编文件。
编译器会将表达式由扫描器(scanner)转化为记号,再由语法分析器(Grammar Parser)转换为语法树(Syntax Tree)(运算符的优先级就在这里体现出来,优先级越高所在层数越大,常量或变量的标识符在最深一层),接着由源码级优化器(Source Code Optimizer)在源代码级别进行优化,产生中间代码(Intermediate Code),再由代码生成器(Code Generator)和目标代码优化器(Target Code Optimizer)产生汇编代码并进行优化并寻址,生成最后的目标文件,也就是一行行的汇编代码。
以上是关于编译器的主要内容,如果未能解决你的问题,请参考以下文章
Java技术指南「编译器专题」深入分析探究“静态编译器”(JAVAIDEAECJ编译器)