你的位置:pcMing工作室 >> 资讯 >> 编程开发 >> C++编程 >> 详细内容 在线投稿

解决VC+++ fatal error LNK1169: one or more multiply错误

排行榜 收藏 打印 发给朋友 举报 来源: 互联网   发布者:未知
热度196票  浏览940次 【共0条评论】【我要评论 时间:2010年3月28日 16:24
pcMing工作室Q9u wP#]'eX2Z

大家都知道,从C/C++源程序到可执行文件要经历两个阶段:(1)编译器将源文件编译成汇编代码,然后由汇编器 (assembler)翻译成机器指令(再加上其它相关信息)后输出到一个个目标文件(object file,VC的编译器编译出的目标文件默认的后缀名是.obj)中;(2)链接器(linker)将一个个的目标文件(或许还会有若干程序库)链接在一起生成一个完整的可执行文件。
*l(W+t(|o])_0pcMing工作室\.Dyt1R*d(e)v
编译器编译源文件时会把源文件的全局符号(global symbol)分成强(strong)和弱(weak)两类传给汇编器,而随后汇编器则将强弱信息编码并保存在目标文件的符号表中。那么何谓强弱呢?编译器认为函数与初始化了的全局变量都是强符号,而未初始化的全局变量则成了弱符号。比如有这么个源文件:
+Q&v`{&l3|0
B{ A|F r(P#]0extern int errorno;
lZ7ZM%X;P%?"Gd!H R0int buf[2] = {1,2};pcMing工作室'n9@,O4t}u8V/Q
int *p;pcMing工作室Dx!}2r \+Pw4v
pcMing工作室m$Hmh C6BB3b
int main()pcMing工作室l8u1O1aZl.N H
{
"M6V4EDy/? q3LD0return 0;pcMing工作室8mg/fV B^ f
}
mL7i-W0q_A0
2nS g3I#Q(F-b m0其中main、buf是强符号,p是弱符号,而errorno则非强非弱,因为它只是个外部变量的使用声明。
yJZ;~e(U;Ms2p(h0pcMing工作室8dx }9E&Rf q
有了强弱符号的概念,我们就可以看看链接器是如何处理与选择被多次定义过的全局符号:
c*W2x2U[&k#z2z0
(v vV/y z0规则1: 不允许强符号被多次定义(即不同的目标文件中不能有同名的强符号);
!H^/KI9|O8wT0pcMing工作室1g:bA^$[ v0^
pcMing工作室!q UgW9h0F5w#h
规则2: 如果一个符号在某个目标文件中是强符号,在其它文件中都是弱符号,那么选择强符号;
G;W7N0^f Hw0pcMing工作室*B"b v.N/A:@%x
pcMing工作室9O$P3\7D z\(R
规则3: 如果一个符号在所有目标文件中都是弱符号,那么选择其中任意一个;
_K-Tn| U0
[:]#Lw'T)})f\0由上可知多个目标文件不能重复定义同名的函数与初始化了的全局变量,否则必然导致LNK2005和LNK1169两种链接错误。可是,有的时候我们并没有在自己的程序中发现这样的重定义现象,却也遇到了此种链接错误,这又是何解?嗯,问题稍微有点儿复杂,容我慢慢道来。
-{2a?3Sj_0pcMing工作室"p;Xqf0C zE

q$Z5So C)r4[#\u0众所周知,ANSI C/C++ 定义了相当多的标准函数,而它们又分布在许多不同的目标文件中,如果直接以目标文件的形式提供给程序员使用的话,就需要他们确切地知道哪个函数存在于哪个目标文件中,并且在链接时显式地指定目标文件名才能成功地生成可执行文件,显然这是一个巨大的负担。所以C语言提供了一种将多个目标文件打包成一个文件的机制,这就是静态程序库(static library)。开发者在链接时只需指定程序库的文件名,链接器就会自动到程序库中寻找那些应用程序确实用到的目标模块,并把(且只把)它们从库中拷贝出来参与构建可执行文件。几乎所有的C/C++开发系统都会把标准函数打包成标准库提供给开发者使用(有不这么做的吗?)。
i:gv2pU-BP@0pcMing工作室J }2As)r[5P X8a)@
程序库为开发者带来了方便,但同时也是某些混乱的根源。我们来看看链接器是如何解析(resolve)对程序库的引用的。
#R){Krw'ragr0pcMing工作室]+a8Yf"Cm&GAW]
在符号解析(symbol resolution)阶段,链接器按照所有目标文件和库文件出现在命令行中的顺序从左至右依次扫描它们,在此期间它要维护若干个集合:(1)集合E是将被合并到一起组成可执行文件的所有目标文件集合;(2)集合U是未解析符号(unresolved symbols,比如已经被引用但是还未被定义的符号)的集合;(3)集合D是所有之前已被加入到E的目标文件定义的符号集合。一开始,E、U、D都是空的。
fLn%l!y(c ]!n6["{A0pcMing工作室"}S-nL z1\J"D
(1): 对命令行中的每一个输入文件f,链接器确定它是目标文件还是库文件,如果它是目标文件,就把f加入到E,并把f中未解析的符号和已定义的符号分别加入到U、D集合中,然后处理下一个输入文件。pcMing工作室6]ug+hBG
pcMing工作室 _F;lS'\:?0B?Fb&m
(2): 如果f是一个库文件,链接器会尝试把U中的所有未解析符号与f中各目标模块定义的符号进行匹配。如果某个目标模块m定义了一个U中的未解析符号,那么就把 m加入到E中,并把m中未解析的符号和已定义的符号分别加入到U、D集合中。不断地对f中的所有目标模块重复这个过程直至到达一个不动点(fixed point),此时U和D不再变化。而那些未加入到E中的f里的目标模块就被简单地丢弃,链接器继续处理下一输入文件。pcMing工作室^{C0m#b t5C$L} U9co
pcMing工作室(~Hi)e5wm F
(3): 如果处理过程中往D加入一个已存在的符号,或者当扫描完所有输入文件时U非空,链接器报错并停止动作。否则,它把E中的所有目标文件合并在一起生成可执行文件。

/tlso[0pcMing工作室!_F#~z"}0ZQ

顶:12 踩:13
对本文中的事件或人物打分:
当前平均分:0.15 (59次打分)
对本篇资讯内容的质量打分:
当前平均分:-0.76 (59次打分)
【已经有53人表态】
13票
感动
8票
路过
8票
高兴
4票
难过
5票
搞笑
6票
愤怒
3票
无聊
6票
同情
上一篇 下一篇
发表评论
换一张

网友评论仅供网友表达个人看法,并不表明本网同意其观点或证实其描述。

查看全部回复【已有0位网友发表了看法】

网络资源