Qt?加載?libjpeg?庫出現(xiàn)“長跳轉(zhuǎn)已經(jīng)運(yùn)行”錯(cuò)誤問題解決
參考資料:Qt5.15.0 升級至 Qt5.15.9 遇到的一些錯(cuò)誤
篇幅有點(diǎn)長,先說解決方法,在編譯靜態(tài)庫時(shí)加上 -qt-libjpeg,編譯出 libjpeg 庫后,在項(xiàng)目中使用 #pragma comment 鏈接即可
OK,開始回顧痛苦經(jīng)歷
在我以為升級到 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
簡單說來,ERREXIT 是官方的 libjpeg 遺留下來的,代碼很古老,至今沒人修,而 libjpeg-turbo 只是包裝了 libjpeg 庫,這樣加載更快,對 libjpeg 中的 api 沒有任何改變,他也可以幫忙包裝下這個(gè)報(bào)錯(cuò),只是要加錢
話說回來,我為何會(huì)遇到 ERREXIT 呢?
那就不得不說 Qt 對 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)該”也能浮出水面了,對,打上雙引號的應(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é):還是對 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)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
到此這篇關(guān)于Qt 加載 libjpeg 庫出現(xiàn)“長跳轉(zhuǎn)已經(jīng)運(yùn)行”錯(cuò)誤問題解決的文章就介紹到這了,更多相關(guān)Qt 加載 libjpeg 庫內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++11標(biāo)準(zhǔn)庫bind函數(shù)應(yīng)用教程
bind函數(shù)定義在頭文件functional中,可以將bind函數(shù)看做成一個(gè)通用的函數(shù)適配器,他接收一個(gè)可調(diào)用對象,生成一個(gè)新的可調(diào)用對象來"適應(yīng)"原對象的參數(shù)列表。本文將帶大家詳細(xì)了解一下bind函數(shù)的應(yīng)用詳解2021-12-12數(shù)據(jù)結(jié)構(gòu)之堆的具體使用
本文主要介紹了數(shù)據(jù)結(jié)構(gòu)之堆的具體使用,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-02-02C語言關(guān)鍵字之a(chǎn)uto register詳解
這篇文章主要為大家介紹了C語言關(guān)鍵字之a(chǎn)uto register,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助2022-01-01C++中為何推薦要把基類析構(gòu)函數(shù)設(shè)置成虛函數(shù)
這篇文章主要介紹了C++中為何推薦要把基類析構(gòu)函數(shù)設(shè)置成虛函數(shù)問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-12-12vs2019永久配置opencv開發(fā)環(huán)境的方法步驟
這篇文章主要介紹了vs2019永久配置opencv開發(fā)環(huán)境的方法步驟,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03C++ push方法與push_back方法的使用與區(qū)別
這篇文章主要介紹了C++ push方法與push_back方法的使用與區(qū)別,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-12-12c++利用stl set_difference對車輛進(jìn)出區(qū)域進(jìn)行判定
這篇文章主要介紹了set_difference,用于求兩個(gè)集合的差集,結(jié)果集合中包含所有屬于第一個(gè)集合但不屬于第二個(gè)集合的元素,需要的朋友可以參考下2017-03-03C語言獲取Shell返回結(jié)果的實(shí)現(xiàn)方法
下面小編就為大家?guī)硪黄狢語言獲取Shell返回結(jié)果的實(shí)現(xiàn)方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2016-07-07