最近在使用VS2013进行静态库链接的时候,发现在最后链接的时候,编译器报告如下警告
1 2 3 4 |
4>LINK : warning C4743: “const std::system_error::`vftable'”在“aaa.cc”和“bbb.cpp”中具有不同的大小: 16 和 12 字节 4>LINK : warning C4743: “const std::_System_error::`vftable'”在“ccc.cc”和“ddd.cpp”中具有不同的大小: 16 和 12 字节 4>LINK : warning C4743: “const std::ios_base::failure::`vftable'”在“eee.cc”和“fff.cpp”中具有不同的大小: 16 和 12 字节 4>LINK : warning C4743: “const std::runtime_error::`vftable'”在“xxx.cc”和“yyy.cpp”中具有不同的大小: 16 和 12 字节 |
尽管这个是个警告,但是由于涉及到vftable 的问题,这个问题会导致对象指针之间相互赋值的时候导致内存布局混乱,非常可能导致严重的问题。因此这个警告的危险级别甚至比错误的还要严重,绝不能简单的忽略这个问题。
研究了很久,发现,在Debug版本上面是没有问题的,但是Release版本上面必然出现该问题。并且当设置VC++ 的 “工程属性->配置属性->C/C++->优化->全程序优化”为 “否”的时候,也是可以无警告链接通过的。但是却会导致我们的工程损失更多的优化,降低运行效率。
这个问题产生的原因是一个宏引起的,这个宏就是 “_HAS_EXCEPTIONS=0” 。这个宏控制了STL对于异常的处理流程,影响着typeinfo,system_error 等几个文件中对于VC 运行时库的链接选择,要么链接libcmt.lib,要么链接msvcrt.lib。比较不凑巧的是,微软在实现这两个库的时候,其中一个比另外一个多了一个虚函数。(这种情况不应该发生,但是确实发生了!)
因此,如果我们的LIB工程定义了“_HAS_EXCEPTIONS=0” ,那么所有使用我们这个LIB的项目,都要定义这个宏。
对于简单的项目,只要都定义“_HAS_EXCEPTIONS=0” 就可以解决问题。但是对于复杂的工程,尤其是依赖了大量的第三方的已经编译过的,没有源代码的LIB项目来说,只能是采用妥协的办法,所有的工程都取消这个宏的定义,使得两者的内存布局相同。毕竟,稳定性是第一需求。