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

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

排行榜 收藏 打印 发给朋友 举报 来源: 互联网   发布者:未知
热度3050票  浏览1602次 【共0条评论】【我要评论 时间:2010年3月28日 16:24
pcMing工作室UXr/nDY+h

P7GW-i/r n s0
'yhw_&mn0
D3n rG7@2n0VC带的编译器名字叫cl.exe,它有这么几个与标准程序库有关的选项: /ML、/MLd、/MT、/MTd、/MD、/MDd。这些选项告诉编译器应用程序想使用什么版本的C标准程序库。/ML(缺省选项)对应单线程静态版的标准程序库(libc.lib);/MT对应多线程静态版标准库(libcmt.lib),此时编译器会自动定义_MT宏;/MD对应多线程DLL版 (导入库msvcrt.lib,DLL是msvcrt.dll),编译器自动定义_MT和_DLL两个宏。后面加d的选项都会让编译器自动多定义一个 _DEBUG宏,表示要使用对应标准库的调试版,因此/MLd对应调试版单线程静态标准库(libcd.lib),/MTd对应调试版多线程静态标准库 (libcmtd.lib),/MDd对应调试版多线程DLL标准库(导入库msvcrtd.lib,DLL是msvcrtd.dll)。虽然我们的确在编译时明白无误地告诉了编译器应用程序希望使用什么版本的标准库,可是当编译器干完了活,轮到链接器开工时它又如何得知一个个目标文件到底在思念谁?为了传递相思,我们的编译器就干了点秘密的勾当。在cl编译出的目标文件中会有一个专门的区域(关心这个区域到底在文件中什么地方的朋友可以参考COFF和 PE文件格式)存放一些指导链接器如何工作的信息,其中有一种就叫缺省库(default library),这些信息指定了一个或多个库文件名,告诉链接器在扫描的时候也把它们加入到输入文件列表中(当然顺序位于在命令行中被指定的输入文件之后)。说到这里,我们先来做个小实验。写个顶顶简单的程序,然后保存为main.c :
C"Y0\8[bj#|'U^0
ZT$sPDr&T$A6K;`X0
i;}o Z/X g0int main() { return 0; }
*u SR@)f2_$[%]%}0
(|N1pa0Bm-z0用下面这个命令编译main.c(什么?你从不用命令行来编译程序?这个......) :
~#f.\A Uk0pcMing工作室"F ~6[Ef;s)n$I
cl /c main.cpcMing工作室q'D1F$o9uH
pcMing工作室4@b6Ra3w
/c是告诉cl只编译源文件,不用链接。因为/ML是缺省选项,所以上述命令也相当于: cl /c /ML main.c 。如果没什么问题的话(要出了问题才是活见鬼!当然除非你的环境变量没有设置好,这时你应该去VC的bin目录下找到vcvars32.bat文件然后运行它。),当前目录下会出现一个main.obj文件,这就是我们可爱的目标文件。随便用一个文本编辑器打开它(是的,文本编辑器,大胆地去做别害怕),搜索"defaultlib"字符串,通常你就会看到这样的东西: "-defaultlib:LIBC -defaultlib:OLDNAMES"。啊哈,没错,这就
t%k!N5F*r)v0是保存在目标文件中的缺省库信息。我们的目标文件显然指定了两个缺省库,一个是单线程静态版标准库libc.lib(这与/ML选项相符),另外一个是oldnames.lib(它是为了兼容微软以前的C/C++开发系统)。pcMing工作室 ~!t2}M{
pcMing工作室M"bL HA_E
VC的链接器是link.exe,因为main.obj保存了缺省库信息,所以可以用pcMing工作室"b5fC;o [ H

6Pa+k*?7rSP-l e0link main.obj libc.lib
P0n8o m;uN0pcMing工作室KvX#}+F
或者
"fU_-~!|X(Ezo'|J^0pcMing工作室_"akW7SV2|v#I
link main.objpcMing工作室o5\:ue|%?

:[e g#o.H ~0来生成可执行文件main.exe,这两个命令是等价的。但是如果你用
vK3H(gU)D0
@.L8yr5I/W4t2t0link main.obj libcd.libpcMing工作室2hS mv2G)H&c!r9eJ
pcMing工作室TB/aX x
的话,链接器会给出一个警告: "warning LNK4098: defaultlib "LIBC" conflicts with use of other libs; use /NODEFAULTLIB:library",因为你显式指定的标准库版本与目标文件的缺省值不一致。通常来说,应该保证链接器合并的所有目标文件指定的缺省标准库版本一致,否则编译器一定会给出上面的警告,而LNK2005和LNK1169链接错误则有时会出现有时不会。那么这个有时到底是什么时候?呵呵,别着急,下面的一切正是为喜欢追根究底的你准备的。pcMing工作室m/` ceY%^ ^1F
pcMing工作室"C/`!\:KkJ"Ii8h!a
建一个源文件,就叫mylib.c,内容如下:pcMing工作室*_W*G,V'A.N)IM

uxF-ib0pcMing工作室v5L%``jua
#i ncludepcMing工作室w.qVP'{b2q

)rC9l2y~mF0void foo()pcMing工作室-[|,t0M$^Ye(P,x
{pcMing工作室8Pl jig,y
printf("%s","I am from mylib!\n");
A3mH3A;u&?:ds0}
loqdt'a:F0pcMing工作室9SAuZ(H3su/~%@/J
pcMing工作室|7m7en7F&j

y b^4g bk `uc0cl /c /MLd mylib.cpcMing工作室3m:? i+sG:Dq9J&DN

~#[;b,t/Ct0命令编译,注意/MLd选项是指定libcd.lib为默认标准库。lib.exe是VC自带的用于将目标文件打包成程序库的命令,所以我们可以用pcMing工作室UdAq U9e.}

f5@gk!]!H{r0lib /OUT:my.lib mylib.objpcMing工作室i0hX,o%|^d

ue0B @.p0将mylib.obj打包成库,输出的库文件名是my.lib。接下来把main.c改成:
V3p6_~Xn0pcMing工作室"P6L3~Tqh'i'^ a!|

1c)F#W\8yW0void foo();pcMing工作室Ns8KI1N^N y1{~K-W

Pwl.V)o U_2j+_u0int main()
N6k `0U+ZM g;]n0{
-g](@Pds+E0foo();pcMing工作室5c.@3W_.SO
return 0;pcMing工作室4TF.LCU%a@h%v{N']
}pcMing工作室#rL.Z2[m#mO4]dD7?

e ]w;x6|$qQ,ky)I0pcMing工作室q*tRBoo0CQR/p0Q m
pcMing工作室Gu%M|dXOx
cl /c main.c
cC2\;n({2a0
3Dg!t S y+]&qwK O0编译,然后用
y9]`{.`L0pcMing工作室 c"Z3D(Qam3L~#b"a
link main.obj my.lib
}hk\-L w y0
1oGR.`5Am%_3lM0进行链接。这个命令能够成功地生成main.exe而不会产生LNK2005和LNK1169链接错误,你仅仅是得到了一条警告信息:"warning LNK4098: defaultlib "LIBCD" conflicts with use of other libs; use /NODEFAULTLIB:library"。我们根据前文所述的扫描规则来分析一下链接器此时做了些啥。
7B`4q%tU-T#J0
OHU$wn@0一开始E、U、D都是空集,链接器首先扫描到main.obj,把它加入E集合,同时把未解析的foo加入U,把main加入D,而且因为 main.obj的默认标准库是libc.lib,所以它被加入到当前输入文件列表的末尾。接着扫描my.lib,因为这是个库,所以会拿当前U中的所有符号(当然现在就一个foo)与my.lib中的所有目标模块(当然也只有一个mylib.obj)依次匹配,看是否有模块定义了U中的符号。结果 mylib.obj确实定义了foo,于是它被加入到E,foo从U转移到D,mylib.obj引用的printf加入到U,同样地,mylib.obj指定的默认标准库是libcd.lib,它也被加到当前输入文件列表的末尾(在libc.lib的后面)。不断地在my.lib库的各模块上进行迭代以匹配U中的符号,直到U、D都不再变化。很明显,现在就已经到达了这么一个不动点,所以接着扫描下一个输入文件,就是 libc.lib。链接器发现libc.lib里的printf.obj里定义有printf,于是printf从U移到D,而printf.obj被加入到E,它定义的所有符号加入到D,它里头的未解析符号加入到U。链接器还会把每个程序都要用到的一些初始化操作所在的目标模块(比如crt0.obj 等)及它们所引用的模块(比如malloc.obj、free.obj等)自动加入到E中,并更新U和D以反应这个变化。事实上,标准库各目标模块里的未解析符号都可以在库内其它模块中找到定义,因此当链接器处理完libc.lib时,U一定是空的。最后处理libcd.lib,因为此时U已经为空,所以链接器会抛弃它里面的所有目标模块从而结束扫描,然后合并E中的目标模块并输出可执行文件。pcMing工作室,t[8[ ]u&J

3Y3jQRU ]@Bv~0

顶:184 踩:158
对本文中的事件或人物打分:
当前平均分:-0.33 (939次打分)
对本篇资讯内容的质量打分:
当前平均分:-0.32 (916次打分)
【已经有853人表态】
118票
感动
118票
路过
91票
高兴
85票
难过
123票
搞笑
92票
愤怒
106票
无聊
120票
同情
上一篇 下一篇
发表评论
换一张

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

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

网络资源