在我以为升级到 Qt5.15.9 后,运行没有什么问题时,问题就来了
在加载 jpeg 格式的图片时,出现了“长跳转已经运行”的错误
这个错误一般是由 setjmp/longjmp 函数触发的,出现的可能的原因有以下几种(听听 chatgpt 的回答)
longjmp 是 C 标准库中的一个函数,用于跳转到之前通过 setjmp 函数设置的跳转点,并在跳转时返回指定的错误码。如果在调用 longjmp 函数时出现错误,通常会表现为程序异常终止、崩溃或死锁等问题。
longjmp 函数可能出现错误的原因和解决方法如下:
- 调用 setjmp 的函数已经返回
使用 longjmp 函数必须要在之前调用过 setjmp 函数并且还没有从 setjmp 函数返回时才能使用。如果在 setjmp 函数返回后再调用 longjmp 函数,就会导致未定义行为,可能会导致程序崩溃或死锁。解决方法是检查 longjmp 函数的调用时机,并确保它是在 setjmp 函数之后而且还没有从 setjmp 函数返回时调用的。
- 跳转目标不存在
当 longjmp 函数尝试跳转到之前设置的跳转点时,如果该跳转点已经不存在,就会导致错误。这种情况通常发生在跳转点所在的函数已经返回或者被释放时。解决方法是检查跳转点是否存在,并确保跳转点所在的函数仍然有效。
- 跨线程调用
longjmp 函数通常不适用于多线程程序。如果在一个线程中设置了跳转点,然后在另一个线程中调用 longjmp 函数来跳转到该点,就会导致未定义行为。解决方法是使用线程安全的异常处理机制来代替 longjmp 和 setjmp 函数。
- 其他原因
除了上述几种情况外,还有可能是其他一些原因导致 longjmp 错误。例如,内存泄漏、非法指针访问、堆栈溢出等问题都可能导致 longjmp 函数失败。解决方法是根据具体错误信息进行排查和修复。
我这边是触发 ERREXIT2 后而跳出的错误
ERREXIT2 的原型如下
触发 ERREXIT2,进入 my_error_exit 函数,然后调用 longjmp,最后程序异常崩溃
为何有这种丑陋的报错呢?官方应该可以把这种报错 catch 下来,而不是让程序闪退,看看 llbjpeg-turbo 作者给出的解释
原始链接:Possibility of non-unwinding error handling
简单说来,ERREXIT 是官方的 libjpeg 遗留下来的,代码很古老,至今没人修,而 libjpeg-turbo 只是包装了 libjpeg 库,这样加载更快,对 libjpeg 中的 api 没有任何改变,他也可以帮忙包装下这个报错,只是要加钱
话说回来,我为何会遇到 ERREXIT 呢?
那就不得不说 Qt 对 5.15 后续版本做出的一些改动了
见:LibJPEG-turbo, version 2.1.5 | Qt GUI 5.15.14
就是说 libjpeg 要你自己去链接,我们不再帮你集成到 qjpeg.lib 中了,可能是协议问题
Independent JPEG Group License and BSD 3-Clause "New" or "Revised" License and zlib License.
既然问题找到了,那解决方法“应该”也能浮出水面了,对,打上双引号的应该
事实上是我低估了这个问题,原本我以为加个 libjpeg-turbo 的库之后就能万事大吉时,结果往往给你一个嘴巴子
我用 vcpkg 包管理器添加了 libjpeg-turbo:x86-windows-static,程序编译通过,也没有出现 ERROR2019 的错误,但是使用 loadFromData 加载 jpeg 图片数据还是会报错
1 2 |
|
我第一反应是 libjpeg-turbo 的库版本太高了,就查阅低版本的库,想通过 vcpkg 新出的版本控制来实现的,奈何水平有限,没弄出来,就去官网下载 2.1.3 的压缩包自己编译
之所以编译 2.1.3 的包,是因为 Qt5.15.9 版本将 libjpeg-turbo 更新至 2.1.3
见:qt/qtreleasenotes.git - Unnamed repository; edit this file 'description' to name the repository.
编译出一个 lib 库后,链接到程序中,还是会报错,嗯,那先排除 libjpeg 版本问题
从堆栈下手吧,一层一层的剥开问题表皮,看本质
报错是停在红框中的 ERREXIT2 中,单步调试后发现,qt 里要求 libjpeg-turbo 的 version 为 80,而 vcpkg 提供的所有 libjpeg-turbo 版本都是 62,可以在 jconfig.h 中查看 version
嗯,80 的为 qt 专属,这就解释了为啥触发了 ERREXIT2 了,顺便说一句,vcpkg 提供的库其实就是官方的库,libjpeg-turbo 不管是 2.1.5 还是 2.1.3,JPEG_LIB_VERSION 都是 62
因此我们只要编译一个 libjpeg 的 qt 三方库就行了
借助这篇教程,
使用 Qt Creator(我使用的 Qt Creator 10.0.0) 打开 libjpeg.pro,再在 .pro 文件里改 lib 输出路径就行
顺便贴上构建设置
可能需要将 jom.exe 改成 nmake.exe(打开 pro 项目后,在构建和运行中选择)
这些都准备后,点击编译即可,在 lib 文件夹中就可以找到了
把库放到项目文件的库目录下,并静态绑定即可
是不是很复杂,直到上一步我也是这么以为的,在我全局搜索 qtlibjpeg.lib 时,我发现 qt 下已经给你编译好了
惊不惊喜意不意外(我都要骂娘了)
重新阅读了官方文档,上面说你可以选择在编译静态库时添加一些参数来一起编译你需要的三方库,比如 libjpeg
见:Qt Configure Options | Qt 6.0
是我大意了,附上编译命令,
1 |
|
编译出的库文件就在 lib 下