记录使用第三方库编译Error LNK2019 无法解析的外部符号问题:wchar_t

1.背景

使用第三方库在编译时出现了链接错误:Error LNK2019 无法解析的外部符号unsigned short* XXXX(XXX);

2.问题分析

使用的第三方库在编译时设置了将wchar_t作为内置类型处理,

而当前开发的程序由于条件限制(依赖的其他库是将wchar_t作为unsigned short处理,并且当前编译环境为某公司在VS上二次开发的编译环境,虽说支持设置编译选项,但开启/Zc:wchar_t后该编译环境却“不认识”),因此要改当前的wchar_t解释是不可行的(当前是作为unsigned short处理),这也是为什么会出现上述问题的原因,当前编译环境将第三方库头文件中的wchar_t认为是unsigned short,等到链接lib文件时发现找不到相应接口的实现(因为lib文件中wchar_t不是unsigned short)。

3.解决方案

先来看下MSDN关于wchar_t的描述,/Zc:wchar_t (wchar_t Is Native Type)

  • /Zc:wchar_t开启:wchar_t作为内置类型(C++标准中定义的2个字节的字符,在Microsoft中是__wchar_t的别名);
  • /Zc:wchar_t-开启:wchar_t作为unsigned short处理;
  • 如果作为C语言编译,wchar_t将作为unsigned short处理,不论当前设置是/Zc:wchar_t还是/Zc:wchar_t-;这也解释了为什么库的导出接口为C(external "C" XXXX)时,在开启/Zc:wchar_t-的程序中使用时没有问题;
  • 微软不推荐编译程序时开启/Zc:wchar_t-,因为C++标准是将wchar_t作为内置类型(2个字节的字符)处理的,因此在Visual Studio中默认开启 /Zc:wchar_t,这时wchar_t是__wchar_t的别名;
  • 开启了/Zc:wchar_t时将会定义两个预处理器符号:_WCHAR_T_DEFINED和_NATIVE_WCHAR_T_DEFINED;

如何设置wchar_t编译选项 ?

在CMake中

set_target_properties,例如,

set_target_properties(CAAMyAddin PROPERTIES COMPILE_FLAGS "/Zc:wchar_t-")

 项目--》属性--》C++ -》语言--》修改 Treat wchar_t as Built-in Type 属性

3.1.开发的库应该怎么设置?

假如开发的库会被旧代码(开启了/Zc:wchar_t-)中使用时该怎么办?微软也给了几种解决方案,

  • 对你的库中使用wchar_t的接口 重载两个版本:一个是将wchar_t替换为unsigned short的版本,另一个是将wchar_t替换为__wchar_t的版本(这两个版本的接口实现都会调用wchar_t的版本),这样你的库既可以在新代码(开启/Zc:wchar_t)和旧代码(开启/Zc:wchar_t-)中使用,是不是很完美?
  • 或者将你的库编译为两个版本:一个是开启了/Zc:wchar_t的,另一个是开启了/Zc:wchar_t-的,这样就需要管理两个版本,额,代价有点大,但问题可以解决;
  • 当然Microsoft建议将旧代码(开启了/Zc:wchar_t-)的编译选项改为新的(即在旧代码中开启/Zc:wchar_t),并且不要在一个程序中混用wchar_t的两种解释(比如当前关于wchar_t的编译选项和库的编译选项不一致);

参考What is __wchar_t (with the leading double underscores) and why am I getting errors about it?

// Something.h

bool DoSomething(const __wchar_t* s);
bool DoSomething(const unsigned short* s);
// Something.cpp
#include <Something.h>

bool DoSomethingWorker(const wchar_t* s)
{
 ... implementation ...
}

bool DoSomething(const __wchar_t* s)
{
    return DoSomethingWorker(reinterpret_cast<const wchar_t*>(s));
}

bool DoSomething(const unsigned short* s)
{
    return DoSomethingWorker(reinterpret_cast<const wchar_t*>(s));
}

3.2.你的程序中使用的库时别人开发的该怎么办?

使用的库是别人开发发布的,而这个库关于wchar_t的解释和你当前的程序不一致,如何是好?

  • 联系库的作者要一份和你当前应用程序设置一样的编译版本的库(如果可能),当然也可自行去找下有没有这样的版本,或者直接将3.1章节中的建议告诉该库的开发者,他按照那样做的话,就没问题了;
  • 如果你的代码是旧的(开启了/Zc:wchar_t-),如果可以的话,那么别再固执了,升级为/Zc:wchar_t吧;
  • 大招来了,直接修改库的头文件(注意别乱修改,否则会出更多的错错误!)中关于wchar_t的接口:将wchar_t替换为__wchar_t或者unsigned short(取决于你当前是/Zc:wchar_t还是/Zc:wchar_t-),为什么这样可以?因为wchar_t只是一个别名,它实际上是__wchar_t或者unsigned short,这里你直接将其替换为对应的真实类型是不会有编译错误的。替换完后,就可以开心的使用了~
  • 当然如果你觉得上述的大招有点残暴,那么你可以选择将库再封装一层,封装好的库提供两个版本的接口,或者干脆将wchar_t换为wstring或者unsigned short!
  • 如果你的程序中使用的不同库的wchar_t设置不一样,那么解决方案和上面的一样~

4.参考

5.总结

正如extern 和 external“C”的分析中所说的那样,我们遇到问题时除了知道怎样解决问题,还应该了解背后的原因,为什么这样就是可以解决的?有没有其他更好的方案?这种问题在谁来处理会更好?知道了原理后,就不仅知道了该问题怎么解决,还知道了这系列问题怎么处理。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

哈市雪花

谢谢啦,欢迎关注wx公众号

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值