Qt?加載?libjpeg?庫出現(xiàn)“長跳轉(zhuǎn)已經(jīng)運(yùn)行”錯(cuò)誤問題解決
參考資料:Qt5.15.0 升級(jí)至 Qt5.15.9 遇到的一些錯(cuò)誤
篇幅有點(diǎn)長,先說解決方法,在編譯靜態(tài)庫時(shí)加上 -qt-libjpeg,編譯出 libjpeg 庫后,在項(xiàng)目中使用 #pragma comment 鏈接即可
OK,開始回顧痛苦經(jīng)歷
在我以為升級(jí)到 Qt5.15.9 后,運(yùn)行沒有什么問題時(shí),問題就來了
在加載 jpeg 格式的圖片時(shí),出現(xiàn)了“長跳轉(zhuǎn)已經(jīng)運(yùn)行”的錯(cuò)誤

這個(gè)錯(cuò)誤一般是由 setjmp/longjmp 函數(shù)觸發(fā)的,出現(xiàn)的可能的原因有以下幾種(聽聽 chatgpt 的回答)
longjmp 是 C 標(biāo)準(zhǔn)庫中的一個(gè)函數(shù),用于跳轉(zhuǎn)到之前通過 setjmp 函數(shù)設(shè)置的跳轉(zhuǎn)點(diǎn),并在跳轉(zhuǎn)時(shí)返回指定的錯(cuò)誤碼。如果在調(diào)用 longjmp 函數(shù)時(shí)出現(xiàn)錯(cuò)誤,通常會(huì)表現(xiàn)為程序異常終止、崩潰或死鎖等問題。
longjmp 函數(shù)可能出現(xiàn)錯(cuò)誤的原因和解決方法如下:
1.調(diào)用 setjmp 的函數(shù)已經(jīng)返回
使用 longjmp 函數(shù)必須要在之前調(diào)用過 setjmp 函數(shù)并且還沒有從 setjmp 函數(shù)返回時(shí)才能使用。如果在 setjmp 函數(shù)返回后再調(diào)用 longjmp 函數(shù),就會(huì)導(dǎo)致未定義行為,可能會(huì)導(dǎo)致程序崩潰或死鎖。解決方法是檢查 longjmp 函數(shù)的調(diào)用時(shí)機(jī),并確保它是在 setjmp 函數(shù)之后而且還沒有從 setjmp 函數(shù)返回時(shí)調(diào)用的。
2.跳轉(zhuǎn)目標(biāo)不存在
當(dāng) longjmp 函數(shù)嘗試跳轉(zhuǎn)到之前設(shè)置的跳轉(zhuǎn)點(diǎn)時(shí),如果該跳轉(zhuǎn)點(diǎn)已經(jīng)不存在,就會(huì)導(dǎo)致錯(cuò)誤。這種情況通常發(fā)生在跳轉(zhuǎn)點(diǎn)所在的函數(shù)已經(jīng)返回或者被釋放時(shí)。解決方法是檢查跳轉(zhuǎn)點(diǎn)是否存在,并確保跳轉(zhuǎn)點(diǎn)所在的函數(shù)仍然有效。
3.跨線程調(diào)用
longjmp 函數(shù)通常不適用于多線程程序。如果在一個(gè)線程中設(shè)置了跳轉(zhuǎn)點(diǎn),然后在另一個(gè)線程中調(diào)用 longjmp 函數(shù)來跳轉(zhuǎn)到該點(diǎn),就會(huì)導(dǎo)致未定義行為。解決方法是使用線程安全的異常處理機(jī)制來代替 longjmp 和 setjmp 函數(shù)。
4.其他原因
除了上述幾種情況外,還有可能是其他一些原因?qū)е?longjmp 錯(cuò)誤。例如,內(nèi)存泄漏、非法指針訪問、堆棧溢出等問題都可能導(dǎo)致 longjmp 函數(shù)失敗。解決方法是根據(jù)具體錯(cuò)誤信息進(jìn)行排查和修復(fù)。
我這邊是觸發(fā) ERREXIT2 后而跳出的錯(cuò)誤
ERREXIT2 的原型如下

觸發(fā) ERREXIT2,進(jìn)入 my_error_exit 函數(shù),然后調(diào)用 longjmp,最后程序異常崩潰
為何有這種丑陋的報(bào)錯(cuò)呢?官方應(yīng)該可以把這種報(bào)錯(cuò) catch 下來,而不是讓程序閃退,看看 llbjpeg-turbo 作者給出的解釋
原始鏈接:Possibility of non-unwinding error handling

簡(jiǎn)單說來,ERREXIT 是官方的 libjpeg 遺留下來的,代碼很古老,至今沒人修,而 libjpeg-turbo 只是包裝了 libjpeg 庫,這樣加載更快,對(duì) libjpeg 中的 api 沒有任何改變,他也可以幫忙包裝下這個(gè)報(bào)錯(cuò),只是要加錢
話說回來,我為何會(huì)遇到 ERREXIT 呢?
那就不得不說 Qt 對(duì) 5.15 后續(xù)版本做出的一些改動(dòng)了

見:https://doc.qt.io/qt-5/qtgui-attribution-libjpeg.html
就是說 libjpeg 要你自己去鏈接,我們不再幫你集成到 qjpeg.lib 中了,可能是協(xié)議問題
Independent JPEG Group License and BSD 3-Clause "New" or "Revised" License and zlib License.
既然問題找到了,那解決方法“應(yīng)該”也能浮出水面了,對(duì),打上雙引號(hào)的應(yīng)該
事實(shí)上是我低估了這個(gè)問題,原本我以為加個(gè) libjpeg-turbo 的庫之后就能萬事大吉時(shí),結(jié)果往往給你一個(gè)嘴巴子
我用 vcpkg 包管理器添加了 libjpeg-turbo:x86-windows-static,程序編譯通過,也沒有出現(xiàn) ERROR2019 的錯(cuò)誤,但是使用 loadFromData 加載 jpeg 圖片數(shù)據(jù)還是會(huì)報(bào)錯(cuò)
QImage photo;
photo.loadFromData(buffer.GetBuffer(), buffer.GetBufferLen()); // buffer 里放置 jpeg 圖片數(shù)據(jù)
我第一反應(yīng)是 libjpeg-turbo 的庫版本太高了,就查閱低版本的庫,想通過 vcpkg 新出的版本控制來實(shí)現(xiàn)的,奈何水平有限,沒弄出來,就去官網(wǎng)下載 2.1.3 的壓縮包自己編譯
之所以編譯 2.1.3 的包,是因?yàn)?Qt5.15.9 版本將 libjpeg-turbo 更新至 2.1.3

見:https://code.qt.io/cgit/qt/qtreleasenotes.git/about/qt/5.15.9/release-note.md
編譯出一個(gè) lib 庫后,鏈接到程序中,還是會(huì)報(bào)錯(cuò),嗯,那先排除 libjpeg 版本問題
從堆棧下手吧,一層一層的剝開問題表皮,看本質(zhì)

報(bào)錯(cuò)是停在紅框中的 ERREXIT2 中,單步調(diào)試后發(fā)現(xiàn),qt 里要求 libjpeg-turbo 的 version 為 80,而 vcpkg 提供的所有 libjpeg-turbo 版本都是 62,可以在 jconfig.h 中查看 version


嗯,80 的為 qt 專屬,這就解釋了為啥觸發(fā)了 ERREXIT2 了,順便說一句,vcpkg 提供的庫其實(shí)就是官方的庫,libjpeg-turbo 不管是 2.1.5 還是 2.1.3,JPEG_LIB_VERSION 都是 62
因此我們只要編譯一個(gè) libjpeg 的 qt 三方庫就行了
參考資料:這篇教程,
使用 Qt Creator(我使用的 Qt Creator 10.0.0) 打開 libjpeg.pro,再在 .pro 文件里改 lib 輸出路徑就行


順便貼上構(gòu)建設(shè)置

可能需要將 jom.exe 改成 nmake.exe(打開 pro 項(xiàng)目后,在構(gòu)建和運(yùn)行中選擇)

這些都準(zhǔn)備后,點(diǎn)擊編譯即可,在 lib 文件夾中就可以找到了

把庫放到項(xiàng)目文件的庫目錄下,并靜態(tài)綁定即可

是不是很復(fù)雜,直到上一步我也是這么以為的,在我全局搜索 qtlibjpeg.lib 時(shí),我發(fā)現(xiàn) qt 下已經(jīng)給你編譯好了

驚不驚喜意不意外(我都要罵娘了)
重新閱讀了官方文檔,上面說你可以選擇在編譯靜態(tài)庫時(shí)添加一些參數(shù)來一起編譯你需要的三方庫,比如 libjpeg

見:https://doc.qt.io/archives/qt-6.0/configure-options.html
是我大意了,附上編譯命令,
configure -static -static-runtime -debug-and-release -mp -prefix "..\msvc2019_x86_static" -opensource -confirm-license -optimize-size -qt-libjpeg -make libs -nomake examples -nomake tests -skip qtwebengine
編譯出的庫文件就在 lib 下

小結(jié):還是對(duì) Qt 的庫配置不熟悉,導(dǎo)致花了大量工夫來解決這種問題;好在有了這次經(jīng)驗(yàn)后,以后再遇到類似問題,就能手到擒來了
到此這篇關(guān)于Qt 加載 libjpeg 庫出現(xiàn)“長跳轉(zhuǎn)已經(jīng)運(yùn)行”錯(cuò)誤的文章就介紹到這了,更多相關(guān)Qt 加載 libjpeg 庫內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
到此這篇關(guān)于Qt 加載 libjpeg 庫出現(xiàn)“長跳轉(zhuǎn)已經(jīng)運(yùn)行”錯(cuò)誤問題解決的文章就介紹到這了,更多相關(guān)Qt 加載 libjpeg 庫內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C語言實(shí)現(xiàn)數(shù)據(jù)結(jié)構(gòu)和雙向鏈表操作
這篇文章主要介紹了C語言實(shí)現(xiàn)數(shù)據(jù)結(jié)構(gòu)雙向鏈表操作,需要的朋友可以參考下2017-03-03
初識(shí)C++的const關(guān)鍵字,常量與常變量
這篇文章主要為大家詳細(xì)介紹了C++的const關(guān)鍵字,常量與常變量,使用數(shù)據(jù)庫,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助2022-03-03
C語言關(guān)于include順序不同導(dǎo)致編譯結(jié)果不同的問題
這篇文章主要介紹了在日常調(diào)試C語言中include的順序不同從而影響最后編譯結(jié)果不同的問題,究其原因是寫代碼的習(xí)慣所導(dǎo)致,下面跟小編一起來看看吧2022-04-04
C++ 非遞歸實(shí)現(xiàn)二叉樹的前中后序遍歷
本文將結(jié)合動(dòng)畫和代碼演示如何通過C++ 非遞歸實(shí)現(xiàn)二叉樹的前中后序的遍歷,代碼具有一定的價(jià)值,感興趣的同學(xué)可以學(xué)習(xí)一下2021-11-11
C語言統(tǒng)計(jì)輸入字符各個(gè)字母出現(xiàn)頻率的解題思路
這篇文章主要介紹了C語言統(tǒng)計(jì)輸入字符各個(gè)字母出現(xiàn)頻率的解題思路,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2015-08-08
VC實(shí)現(xiàn)獲取本機(jī)MAC地址的方法
這篇文章主要介紹了VC實(shí)現(xiàn)獲取本機(jī)MAC地址的方法,需要的朋友可以參考下2014-07-07

