编译过程

在编写完程序,在编译器的菜单里选择“编译”后,编译器所做的大致可以分为三个过程:首先,代码通过一个预处理器(preprocessor),这个预处理器会识别出代码的有关元信息。其次,代码经过编译(compile),或翻译为机器可读的对象文件。最后,单个的对象文件链接(link)到一起,构成了一个应用。在vc中编译选项的设置里,“C++”中设置的是与编译过程相关的项,在“链接器”中设置的是与链接相关的项。

预处理器是在真正的翻译开始之前由编译器调用的独立程序。预处理器可以删除注释、包含其他文件以及执行宏替代。包含文件就是把包含的头文件内容替换在include该文件语句的位置。使用头文件要注意的是要避免同一个头文件的循环引用和多重包含。#ifndef机制和#program once可以用于避免循环包含和多重包含,如果使用vc的菜单中的添加新类,则会自动添加上述机制的一种(依编译器版本而定)。要避免头文件的这些问题,另一种工具是超前引用。如果需要引用一个类,但是不能包含它的头文件(比如,因为这个类相当依赖于你正在编写的类),那么可以只是告诉编译器存在这样的一个类(如下所示),而不是通过#include机制提供正式的类定义。当然,还不能在代码中真正使用这个类,因为编译器只是知道会有这样一个类存在。不过,还是可以在类定义中使用指向这个类的指针或者引用。

class AnotherClass;

class OneClass

{

  public:

  AnotherClass m_Test;

 }

此外,由于包含文件就是在include的位置换上包含的文件。那么,如果类声明中需要另一类,则不一定要在头文件中包含另一类的头文件,也可以在cpp文件中包含另一个类的头文件,但该include文件的位置要在include本类头文件的前面,即:

编译过程[转] - 莎莎 - 学海无涯//client.cpp

编译过程[转] - 莎莎 - 学海无涯#include "StdAfx.h"

编译过程[转] - 莎莎 - 学海无涯#include "RealInterface.h"

编译过程[转] - 莎莎 - 学海无涯#include "Client.h"

编译过程[转] - 莎莎 - 学海无涯但是编译时还是可能会报错,如“missing type specifier”, "syntax error : missing ',' before identifier '","undeclared identifier"。那么就要看该头文件(如上例是client.h)有没有在其他cpp文件中被包含,有的话则也需在其前面加上所需的其他头文件(如上例是RealInterface.h)。

这其实涉及到下面要说的编译的一些特点。编译是分别编译单个实现文件,将其转换为机器代码,那么这个阶段会检查语法等,符合语法的才能被转换为机器代码。但当有多个实现文件时,编译器不能保证其编译的顺序,而且在这一阶段只检查单个文件的合法性。那么如前所述的超前引用,尽管只是声明,就可以编译通过,因为从语法上讲是合理的了。

编译阶段可能出现的错误很多,这里不想总结了。因为语法错误的可能太多了。

链接则是要将单个的对象文件链接(link)到一起,形成一个可执行文件了。这个过程就不再允许任何错误了。那么既然编译时已经检查了语法错误,这里还会有错误吗?常见的就是“无法解析的外部符号”和“发现重复的定义”。前者的原因是编译器只找到了函数或类的声明,而没有找到实现;后者是找到了两个实现。

造成“无法解析的外部符号”的情况有很多,如前所述的超前引用,如果你只是给出了一个声明,没有在其他文件给出实现,这是很明显的没有实现;还有隐蔽的一些是,使用了其他dll的导出函数,但却没有链接其导入库。

还有总结一下最近在项目中遇到的一些命名空间的链接错误。个人编程时命名空间很少用,到了公司后作产品才开始使用。最近遇到的情况有:不小心把一个包含头文件的语句放到了命名空间内,但实际上该头文件和实现文件并没有声明在该命名空间内,这样把包含文件的语句放入命名空间内,则声明在命名空间内,但在命名空间内找不到实现,就会有链接错误;把声明全局对象的语句放到了命名空间内,则在另一个cpp文件(属另一个命名空间)要用到该对象时,想将其声明为extern,则也要将其包含在原命名空间内,否则链接错误,因为会在同一作用域内去找原来定义的全局对象;如果把全局对象原来的定义放在外面,也是链接错误,因为在全局作用域内,找不到该类的实现,它的实现在命名空间内。 

造成“发现重复的定义”的情况一般都能找到原因。不过想阐述一下:C++源文件中的每个名字,包括函数和全局变量,都有一个链接,可能是内部链接,也可能是外部链接。外部链接是指,对于其他源文件,这个名字是可用的。内部链接是指对于其他源文件,这个名字不可用。函数和全局变量默认有外部链接,但是可以在声明前加上关键字static,来指定内部链接。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值