xml地图|网站地图|网站标签 [设为首页] [加入收藏]

应用程序文件的编译过程,声明符号

来源:http://www.ccidsi.com 作者:集成经验 人气:154 发布时间:2019-11-13
摘要:c 预申明类引发的无法拆解分析外界符号难点,注脚符号 在VisualStudio下支付C 程序常境遇链接难题正是:LNK2019 不能解析外部符号. 这一个标题日常大家以为是平素不将援引的代码链接到

c 预申明类引发的无法拆解分析外界符号难点,注脚符号

在VisualStudio下支付C 程序常境遇链接难题正是:LNK2019 不能解析外部符号.

这一个标题日常大家以为是平素不将援引的代码链接到当前项目引致,也许有例外,便是上边笔者要说的预注脚类以致的。

为了加紧编写翻译速度,我们常常筛选在头文件中预注明类占个名字用于指针,在代码定义文件中再去蕴涵完整的类评释。

foo.h:

class foo

{

public:

  void call(){};

}

 

bar.h:

class foo;

foo* f=0;

 

bar.cpp:

#include "bar.h"

#include "foo.h"

int main(){f->call();return 0;}

 

当境遇编写翻译单元(日常指cpp文件卡塔 尔(阿拉伯语:قطر‎现身涉及援用(A用B,B用C卡塔 尔(英语:State of Qatar)时,三回援引此中两个从未有过蕴含最终引用对象(C卡塔 尔(英语:State of Qatar)的宣示时也会生出“无法深入深入分析外部符号.”

例如:

foo.h:

class foo

{

public:

  void call(){};

}

 

bar.h:

class foo;

void barcall(foo* f=0);

 

bar.cpp:

#include "bar.h"

foo* store;

void barcall(foo* arg)

{

  store = arg;

}

 

main.cpp:

#include "foo.h"

#include "bar.h"

int main()

{

  barcall(0);

  return 0;

}

 

编译时的main.cpp中的foo类是总体的宣示,而bar.cpp中的foo类仅仅是叁个空的组织(预订义的卡塔尔,所以编译器会断定他们是莫衷一是的构造,以致找不到要找的要命暗记。

此例中是因为bar.cpp中尚无包蕴foo.h,所以foo的结构仅仅是个空结构,与main.cpp中对barcall援用的foo结构是不一样的,发生找不到符号的链接错误。

解决办法是在bar.cpp中含有foo.h来得到foo的全体表明。

 

在VisualStudio下支付C 程序常蒙受链接难点正是:LNK2019 不可能剖析外界符号. 那几个主题素材风流倜傥...

    2):存在豆蔻梢头种恐怕,即一个cpp文件直接的或许直接的不外乎了累累同七个.h文本。下边就是那般的风华正茂种状态:

地点的代码张开后就也就是同有时间在main.cpp中定义了七个变量i。因而将生出编写翻译错误。消除办法是使用#ifndef或者#pragma once宏,使得test.h只可以在main.cpp中被含有一次。关于#ifndef和#pragma once请参考这里。

图片 1

2):把main.cpp文件中,第7行的笺注符号去掉。即插足类模板的实例化代码。在编写翻译工程,会开采也能够编写翻译通过。回顾一下那一个进度,testTemplate.h被开展,也正是说main.cpp在编写翻译是就会找到MyClass<T>的宣示。那么,在编译第7行的时候就能够健康的实例化八个类模板出来。这里注意:类模板的分子函数唯有在调用的时候才会被实例化。因而,由于还未有对类模板成员函数的调用,编写翻译器也就不会去查找类模板的兑今世码。所以,下边包车型地铁函数能编写翻译通过。

 1 // ===========test.h============
 2 // 声明意气风发(Wissu卡塔 尔(英语:State of Qatar)个函数。注意后边没有分号。
 3 void foo()
 4 
 5 // ===========test1.h===========
 6 // 仅写了一个支行。
 7 ;
 8 
 9 // ===========main.cpp=========
10 // 注意,这里依照test.h和test1.h的逐一饱含了头文件。
11 #include "stdafx.h"
12 #include "test.h"
13 #include "test1.h"
14 
15 int _tmain(int argc, _TCHAR* argv[])
16 {
17     return 0;
18 }

假诺单独看上面的代码中,test.h后面需求叁个子公司技能编写翻译通过。而test1.h中定义的分局赶巧能够补上test.h前面差的不行分号。由此,安那样的种种定义在main.cpp中后都能不荒谬的编写翻译通过。就算在事实上项目中并不推荐那样做,但以此例子能够表明超多关于文件富含的内容。
有些人可能见到了,上边的事必躬亲中固然声称了二个函数,但不曾落到实处且还是能够通过编译。那正是上边cpp文件编写翻译时的从头到尾的经过了。

此间讲下C 文件的编写翻译进度及其间模板的编写翻译进程;

  1. 在cpp文件中展开include文件。
  2. 将每一种cpp文件编写翻译为三个相应的obj文件。
  3. 连接obj文件成为一个exe文件(或许其余的库文件卡塔尔。

 1 #include "stdafx.h"
 2 //#include "test.h"
 3 
 4 void foo();
 5 
 6 int _tmain(int argc, _TCHAR* argv[])
 7 {
 8     // foo();
 9 
10     return 0;
11 }

现行反革命做个例如,foo()的达成并不确实存在会什么?先看上边包车型客车代码:

图片 2

 1 // ===========test.h============
 2 // 定义贰个变量
 3 int i;
 4 
 5 // ===========test1.h===========
 6 // 包含了test.h文件
 7 #include "test.h"
 8 
 9 // ===========main.cpp=========
10 // 这里还要满含了test.h和test1.h,
11 // 也等于说同不经常间定义了七个变量i。
12 // 将时有发生编写翻译错误。
13 #include "stdafx.h"
14 #include "test.h"
15 #include "test1.h"
16 
17 void foo();
18 void foo();
19 
20 int _tmain(int argc, _TCHAR* argv[])
21 {
22     return 0;
23 }

图片 3

 1 #include "stdafx.h"
 2 //#include "test.h"
 3 
 4 void foo();
 5 
 6 int _tmain(int argc, _TCHAR* argv[])
 7 {
 8     foo();
 9 
10     return 0;
11 }

专心到22行对foo函数实行了调用。上边的代码的实操进程是编写翻译器首先为种种cpp文件生成了二个obj,这里是test.obj和main.obj(还应该有一个stdafx.obj,那是出于应用了VS编辑器卡塔尔。但此间有个难题,尽管test.h对main.cpp是可以知道的(main.cpp包蕴了test.h卡塔 尔(英语:State of Qatar),但是test.cpp对main.cpp并不可以知道,那么main.cpp是怎么着找到foo函数的贯彻的吗?实际上,在单身编译main.cpp文件的时候编译器并不先去关怀foo函数是或不是早就贯彻,可能在何地完成。它只是把它看成三个外部的链接类型,以为foo函数的兑现应有在其它的一个obj文件中。在22行调用foo的时候,编写翻译器仅仅使用了二个地方跳转,即jump 0x23423之类的事物。可是由于并不知道foo具体存在于哪个地方,由此只是在jump前面填入了八个假的地址(具体应该是怎么着还请大师指教卡塔 尔(英语:State of Qatar)。然后就连续编写翻译上面包车型大巴代码。当全部的cpp文件都试行完了后头就进来链接阶段。由于.obj和.exe的格式都以同等的,在此样的公文中有贰个标识导入表和标识导出表[import table和export table]里头将具备符号和它们之处关联起来。那样连接器只要在test.obj的标识导出表中找寻符号foo[当然C 对foo作了mapping]的 地址就能够了,然后作一些偏移量管理后[因为是将八个.obj文件合併,当然地址会有一定的偏移,那么些连接器清楚]写入main.obj中的符号导入表中foo所占有的那风流洒脱项。那样foo就能够被成功的实施了。

2.CPP文本的编写翻译和链接。
世家都晓得,C 的编写翻译实际上分为编写翻译和链接三个阶段,由于那七个品级联系紧密。由此放在一块儿来证实。在编写翻译的时候,编写翻译器会为各种cpp文件生成叁个obj文件。obj文件具有PE[Portable Executable,即windows可试行文件]文件格式,并且小编蕴藏的就曾经是二进制码,然而,不料定能够实践,因为并不保证内部自然有main函数。当全数的cpp文件都编写翻译好了后头将会借助必要,将obj文件链接成为一个exe文件(可能别的方式的库卡塔尔。看上边包车型大巴代码:

这里唯有foo的宣示,大家把原来的foo的调用也去掉了。上边包车型大巴代码能编写翻译通过。原因便是出于还没调用foo函数,main.cpp未有真的的去找foo的落到实处(main.obj内部依旧main.obj外界卡塔 尔(阿拉伯语:قطر‎,编写翻译器也就不会在乎foo是或不是早就贯彻了。

图片 4

4):既然是由于找不到testTemplate.cpp文件,那么我们就将testTemplate.cpp文件包涵在工程中。再一次编写翻译,在VS中会提示二个链接错误,说找不到表面类型_thiscall MyClass<int>::PrintValue(int)。只怕你会认为很意外,我们已经将testTemplate.cpp文件包蕴在了工程中了阿。先思谋三个标题,大家说过模板的编写翻译实际上是二个实例化的经过,它并不编写翻译爆发二进制代码。其余,模板成员函数也独有在被调用的时候才会开首化。在testTemplate.cpp文件中,由于包罗了testTemplate.h头文件,因而那是八个单身的能够编写翻译的类模板。但是,编写翻译器在编译那几个testTemplate.cpp文件的时候是因为还未别的成员函数被调用,因而并未实例化PrintValue成员。可能你会说俺们在main.cpp中调用了PrintValue函数。可是要领会testTemplate.cpp和main.cpp是七个单身的编写翻译单元,他们彼此之间间并不知道对方的表现。由此,testTemplate.cpp在编译的时候其实照旧只编写翻译了testTemplate.h中的内容,即再一次宣称了模版,并不曾实例化PrintValue成员。所以,当main.cpp开掘必要PrintValue成员,并在testTemplate.obj中去追寻的时候就能够找不到指标函数。进而产生一个链接错误。

5):综上所述,模板代码不能够依照常规的C/C 代码来企业。必需得保险使用模板的函数在编写翻译的时候就会找到模板代码,进而实例化模板。在网络有那三个关于那上头的小说。首要将模板编写翻译分为包括编写翻译和分手工编织译。其实,不管是含有编写翻译照旧分别编写翻译,皆以为了一个对象:使得实例化模板的时候就会找到呼应的沙盘实现代码。大家能够参考那篇小说。

再看上边包车型大巴三个例子:

图片 5

图片 6

二:模板的编写翻译进度。
    在领略了C 程序的编译进度后再来看模板的编写翻译进程。大家领略,模板须求被模板参数实例化成为多少个现实的类照旧函数技巧动用。但是,类模板成员函数的调用且有三个很主要的特点,那正是成员函数唯有在被调用的时候才会被发轫化。便是由于那脾性情,使得类模板的代码无法依照常规的C 类相通来组织。先看上边包车型客车代码:

本文由68399皇家赌场发布于集成经验,转载请注明出处:应用程序文件的编译过程,声明符号

关键词: 68399皇家赌场 其他分类 转载区 编程语言-C++

频道精选

最火资讯