wxStringData::Free() link error

本文详细解释了在使用Visual C++编译wxWidgets时遇到的链接错误问题,并提供了两种解决方案:一是选择合适的链接选项来编译应用,二是重新编译wxWidgets库以匹配应用的链接需求。深入探讨了wxString类内部的内存管理机制,以及为何会出现此链接错误。

問題描述

有時我們在 Visual C++ 中編譯 wxWigets 的程式時,會出現類似下面的錯誤訊息,導致連結失敗:

1>BoardManager.obj: error LNK2019: unresolved external symbol "public: void __thiscallwxStringData::Free(void)" (?Free@wxStringData@@QAEXXZ) referenced infunction "public: void __thiscall wxStringData::Unlock(void)"(?Unlock@wxStringData@@QAEXXZ)

1>MyApp.obj :error LNK2001: unresolved external symbol "public: void __thiscallwxStringData::Free(void)" (?Free@wxStringData@@QAEXXZ)

1>MyFrame.obj :error LNK2001: unresolved external symbol "public: void __thiscallwxStringData::Free(void)" (?Free@wxStringData@@QAEXXZ)

1>ViewerDlg.obj: error LNK2001: unresolved external symbol "public: void __thiscallwxStringData::Free(void)" (?Free@wxStringData@@QAEXXZ)

直接從錯誤訊息字面上來解釋的話是說:「連結器在連結時找不到 void __thiscall wxStringData::Free(void) 的定義」。這個現象的主因是:wxWidgets 在使用 static run-timelibrary(意即非 DLL)時,會定義並使用 wxStringData::Free() 這個函式;而當使用 dynamic run-time library(意即 DLL)時,這個函式就沒有定義,也沒有用到了。(至於為什麼會有這樣的差別,請參閱後面的詳細解說

因此,若是我們在一開始編譯 wxWidgets 函式庫時,"RuntimeLibrary" 這個選項使用"Multi-threaded (Debug) DLL",而編譯應用程式時使用 "Multi-threaded (Debug)"(沒有 DLL)的話,就會發生這個問題。


解決方法

1.    在編譯應用程式的時候,選用 "Multi-threaded DLL (/MD)"(若要編譯 Release 版)或是"Multi-threaded Debug DLL (/MDd)"(若要編譯 Debug 版)。

這麼做的缺點是:編譯出來的執行檔無法在「未安裝 Visual C++ Cruntime 函式庫」的電腦上執行。若是你想要 release 執行檔給其他的使用者,你必須同時幫他們準備Visual C++ Cruntime 函式庫

2.    使用 "Multi-threaded (Debug) DLL" 選項,重新編譯 wxWidgets 函式庫。詳細方法請參閱這篇

這麼做的缺點是執行檔會比較大,同時 wxString 相關的記憶體管理也會比較沒有效率。

深入探討

wxString 這個類別內部使用了wxStringData 這個結構儲存字串的內容。wxStringData 提供了 Lock() Unlock() 這組函式,實作 reference counting。當 wxStringData::Unlock() 被呼叫,而且 counter 減到 0 的時候,wxStringData 就會把配置的記憶體釋放掉(呼叫free() 函式)。

為了增進效率,wxStringData::Unlock() 是以行內 (inline) 的方式實作在 wx/string.h 裡面的。因此當我們在編譯程式的時候,Unlock()的程式碼會直接產生在我們撰寫的程式中,包括釋放記憶體的相關程式碼;而配置記憶體相關的程式碼則不是以行內方式實作,因此會被包含在 wxWidgets 函式庫中。

當我們使用 Visual C++ 的時候,若是我們直接使用靜態連結的C run-time 函式庫(選用 "Multi-threaded DEBUG" 或是 "Multi-threaded"),記憶體配置和釋放必須在同一個 DLL 內完成(詳細的原因我找不到,不過我猜是為了避免連結到不同版本的配置/釋放函式)。從前段可知:若是我們仍將呼叫 free() 的程式碼放在 wxStringData::Unlock() 中的話,就會發生「配置和釋放在不同的 DLL」的問題。wxWidgets 解決這個問題的方法,另外實作一個「非行內」的wxStringData::Free(),裡面呼叫 free(),讓配置和釋放在同一個 DLL 中。但另一方面又不希望影響到其他設定下的效率,因此這個方法只有「在 Visual C++ 下,使用 Multi-threaded,同時不使用 DLL」的時候才採用。相關程式碼如下:

//------------------
//  string.h
//------------------
 
#if defined(__VISUALC__) && defined(_MT) && !defined(_DLL)
  void  Unlock() { if ( !IsEmpty() && --nRefs == 0) Free();  }
  void  Free();
#else
  void  Unlock() { if ( !IsEmpty() && --nRefs == 0) free(this);  }
#endif
 
//------------------
//  string.cpp
//------------------
 
#if defined(__VISUALC__) && defined(_MT) && !defined(_DLL)
void wxStringData::Free()
{
    free(this);
}
#endif
 

現在回到我們原本的問題上。當我們選用 "Multi-threadedDLL" 編譯wxWidgets 時,因為此時 _DLL 被定義了,所以 string.cpp 中的 wxStringData::Free() 不會被編譯進去。因此,當我們選用"Multi-threaded" 編譯我們的應用程式時,就會找不到 wxStringData::Free() 的實作碼了。

參考資料

 From: http://www.cclo.idv.tw/blogs/wxwidgets/2008/12/wxstringdatafree.html

"Mstar Bin Tool"是一款专门针对Mstar系列芯片开发的固件处理软件,主要用于智能电视及相关电子设备的系统维护与深度定制。该工具包特别标注了"LETV USB SCRIPT"模块,表明其对乐视品牌设备具有兼容性,能够通过USB通信协议执行固件读写操作。作为一款专业的固件编辑器,它允许技术人员对Mstar芯片的底层二进制文件进行解析、修改与重构,从而实现系统功能的调整、性能优化或故障修复。 工具包中的核心组件包括固件编译环境、设备通信脚本、操作界面及技术文档等。其中"letv_usb_script"是一套针对乐视设备的自动化操作程序,可指导用户完成固件烧录全过程。而"mstar_bin"模块则专门处理芯片的二进制数据文件,支持固件版本的升级、降级或个性化定制。工具采用7-Zip压缩格式封装,用户需先使用解压软件提取文件内容。 操作前需确认目标设备采用Mstar芯片架构并具备完好的USB接口。建议预先备份设备原始固件作为恢复保障。通过编辑器修改固件参数时,可调整系统配置、增删功能模块或修复已知缺陷。执行刷机操作时需严格遵循脚本指示的步骤顺序,保持设备供电稳定,避免中断导致硬件损坏。该工具适用于具备嵌入式系统知识的开发人员或高级用户,在进行设备定制化开发、系统调试或维护修复时使用。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值