2010年3月11日星期四

Visual C++ STL 相关编译错误的解决办法

和所有的垄断企业一样,微软的做法经常是武断和专横的,一个困扰了我一个多月的问题解决了,结果竟是如此的不可思议。有一个库的binary是在VC 2005下编译的,如果用VC 2008编译例程link用VC 2005的库文件时程序会Crash,所以只能用回VC 2005编译例程。在用VC 2005编译例程的时候,link时出现了这样的错误:

error LNK2001: unresolved external symbol "void __cdecl std::_Throw(class stdext::exception const &)" (?_Throw@std@@YAXABVexception@stdext@@@Z)
error LNK2001: unresolved external symbol "void (__cdecl* std::_Raise_handler)(class stdext::exception const &)" (?_Raise_handler@std@@3P6AXABVexception@stdext@@@ZA)

在网上搜了大半天,没有任何头绪,把Windows SDK升级了也不能解决问题。忽然记起用VC 2008编译时是可以通过的,搜索stdext::exception时,发现网上有些地方贴出来的类似的出错的提示信息中显示的exception头文件中,stdext::exception定义所在的行数和VC 2005中exception头文件不符,才怀疑VC 2005到VC 2008的头文件有变化,结果发现,在VC 2005中,exception是放在std的namespace中,而VC 2008的exception是放在stdext的namespace中。但是这个库的Binary为什么是在VC 2005下编译,但是用的又是stdext::exception呢?突然想到微软经常会出SP1,SP2这些东西,下了VC 2005 SP1安装之后,编译通过。据说,VC 2010还会把一些类从std移入stdext,但是为什么要把类移来移去造成混乱呢,没有找到答案。

所有高度依赖STL的VC程序都会有类似的问题,所以一般都会写明要升级到VC 2005 SP1:

 其中提到的另外一种编译错误:

LIBCMTD.lib(stdexcpt.obj) : error LNK2005: "public: virtual __thiscall std::exception::~exception(void)" (??1exception@std@@UAE@XZ) already defined in mksnapshot.obj
LIBCMTD.lib(stdexcpt.obj) : error LNK2005: "public: virtual char const * __thiscall std::exception::what(void)const " (?what@exception@std@@UBEPBDXZ) already defined in mksnapshot.obj