解读C++编译报错有迹可寻
作者:111尽力而为
1. 什么是编译
1.1. 计算机程序设计语言的三个层次
在计算机系统中,主要有三种层次的语言,他们是机器语言、汇编语言、高级语言。
机器语言是可以被计算机理解的语言,计算机只能理解01二进制序列,但是机器语言特别难记。
汇编语言在机器语言的基础上引入了助记符,方便记忆一些,但是要熟悉目标机器的指令特点,使用效率低,对人要求高。
正是如此引用高级语言,高级语言采用类似数学定义或者自然语言的简洁形式,接近人的习惯并不依赖特定机器。
图1 -1计算机程序设计语言的三个层次
1.2. 三种语言的关系
高级语言和汇编语言都要翻译成机器语言才能在计算机上执行,其中将高级语言转换成汇编语言或者机器语言的过程叫做编译,将汇编语言转换成机器语言叫做汇编。
编译的本质是将高级语言转换成汇编语言或者机器语言的过程,其中高级语言就是源语言、汇编语言或机器语言就是目标语言。
2. 计算机语言处理系统
编译器是计算机语言处理系统的核心部件,但在计算机语言处理系统中,除了编译器,还有预处理器、汇编器、链接器。
图2-1 计算机语言处理系统
预处理器的作用是把存储在不同文件中的源程序聚合在一起;把称为宏的缩写语句转换成原始语句。
编译器的作用是把高级语言翻译成汇编语言。
汇编器的作用是把汇编语言程序转换成可重定向的机器代码。可重定向的意思是汇编器所生成的这段代码在内存中存放的开始位置不是固定的,代码中所有地址都是相对起始地址的相对地址。起始地址+相对地址=绝对地址(内存中地址)。
链接器的作用是将多个可重定向的机器代码文件(包括库文件)链接在一起,也解决外部地址问题。所谓的外部地址问题是一个文件代码引用了另外一个文件中的数据对象或者过程,那这个数据对象或者过程地址就是外部文件地址。
3. 编译系统的结构
编译系统的本质正是将高级语言翻译成汇编语言或者机器语言,那么如何翻译?
3.1. 人工翻译英文到汉文的例子
In the room,he broke a window with a hammer.
这个英文翻译成汉语,主要分成两个步骤,见图3-1。这里的源语言就是英语,目标语言就是汉语。
图3-1 英汉翻译的一般方法
分析过程如下:
1)找到最关键的谓语break。
2)然后进行主语谓语宾语的分析
图3-2 英语句子成分划分
3)用中间形式表示语义
图3-3 语义表示
4)根据图的意思用汉语翻译
在房间里,他用锤子砸了一扇窗户。
3.2. 语义分析过程的一点启发
通过以上的分析,完成翻译就是理解句子的语义,也就是语义分析。
要进行语义分析,需要知道短语的结构,需要先进行语法分析,通过语法分析划分句子成分。句子成分是由单词构成的,因此需要通过词法分析获取词类。
一张图解释词法分析,语法分析,语义分析的关系,见图3-4。
图3-4 词法分析语法分析语义分析的关系
3.3. 编译器的结构
正如前面讨论的那样子,编译器翻译的核心就是找到语义。实际的编译器的结构如下3-5。
围绕语义分析,形成前端分析部分,与源语言有关。围绕目标语言生成构成后端综合部分,与目标语言有关。
而语义的中间表示形式,与目标语言无关,从而与目标机器无关。
其中词法分析器、语法分析器、语义分析器、中间代码生成器构成编译的核心。
图3-5 编译器的结构
4. 自动化编译系统
在计算机语言处理系统中,解决了源文件和库文件到最终的可执行文件的过程。这个过程可以看做是一个输入输出系统。
输入的是源文件(*.h,*.cpp)或者库文件(*.h,*.so),输出的是可执行文件(*.elf)或者库(*.so)。
对于这一过程进行输入输出管理的过程需要搭建自动化编译系统,它由make、makefile以及计算机语言处理系统构成。
图4-1 自动化编译系统
- Makefile作用
它保存了编译器和链接器的参数选项,还表达了所有源文件之间的依赖关系。makefile关系到了整个工程的编译规则。
一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为makefile就像一个Shell脚本一样,其中也可以执行操作系统的命令。
- Make作用
Make是一种程序,它首先读取makefile文件,然后调用编译器、汇编器、链接器以便产生最终的可执行文件和库。
5. 编译报错
5.1. 编译报错的本质
经过上述对自动化编译系统的概述,以及对计算机语言处理系统的概述。我们可以推测编译报错的本质就是自动化编译系统报错,自动化编译系统作为一个输入输出系统,非法的输入或者空的输入自然会引起编译报错。
makefile管理整个工程的源文件和库文件,以及计算机语言处理系统中的预处理器、编译器、汇编器、链接器。从上述的编译原理讨论不难总结出几个典型的编译报错类型:
- 输入的makefile文件中存在makefile语法错误,将会导致make报错。计算机语言处理系统参数设置不正确,或环境路径错误将会导致make报错。
- 输入的源文件中存在C++语言的预处理语法错误,将会导致预处理器编译报错。
- 输入的源文件中存在C++语言中的词法、语法、语义错误,将导致编译器报错。
- 输入的源文件中存在C++语言中库使用错误,将导致编译器报错。
- 输入的库文件和源文件存在C++语言中的语法错误,导致链接器报错。或者输入的库文件和源文件存在环境路径错误,将导致链接器报错。
5.2. makefile报错
- Makefile语法错误
- 编译器参数设置错误
5.3. 预处理报错
- C++宏定义错误
5.4. 源程序编译报错
- C++词法错误
- C++语法错误
- C++语义错误
- C++的类库使用错误
5.5. 库链接报错
- C++语法错误
- 库头文件与库本身不匹配错误
5.6. 其他错误
- 路径配置错误
- 文件权限获取错误
- 源文件未及时保存错误
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。