如何解决 C/C++ 编译器优化导致的编译BUG(程序崩溃)支援VC++/CLANG/GCC

本文主要是介绍如何解决 C/C++ 编译器优化导致的编译BUG(程序崩溃)支援VC++/CLANG/GCC,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

本文仅适用于,有愿意、爱捣鼓的童靴。

因编译器优化导致编译BUG,即DEBUG下面无故障稳定工作,但RELESE下程序会在特定函数位置上崩溃。

这要求 C/C++ 开发人员拥有最基本的素质,需要能够承受,逐行审视编译器输出的目标平台汇编代码、从函数崩溃点往上(及整个汇编函数段内)逐行审视分析的苦逼。

大多数简单的 C/C++ 开发的程序,并不需要这样的捣鼓,但当 C/C++ 大量的应用宏、模板元编程的时候,遭遇类似的编译器BUG,将无法避免。

我们既无法要求、或寄托开发编译器的人们,能够解决这个问题,因为这个事情,遥遥无期,所以,这需要童靴们,要有自己动手折腾的能力。

看汇编是为了知道,C/C++ 在把代码翻译为汇编代码的时候,到底出现了什么问题,

例如:

1、常数100,变成250

2、汇编调用了错误地址

3、汇编之中,对于 C/C++ 结构内存对齐不正确

4、错误的优化导致的崩溃,如内链接代码错误(inline BUG)

5、寄存器优化BUG(寄存器被复用,致程序读写值错误)

根据审视这些汇编代码,来推论属于哪一类的情况,但通常,我们并不需要这么复杂的具体分析,这么分析是为了最高效能,极致 C/C++ 代码性能吞吐优化,所以需要细微入致,谨慎分析、代码调效。

如果你不能通过汇编定位到,优化导致BUG的位置,你将无法通过控制 C/C++ 编译器指令禁止优化,或者减少优化级别来解决这个问题。

所以,本文说的很明白,不适合没有这种精气神,跟捣鼓的童靴,如果只是会点 C/C++ 语法,写点 C/C++ 程序,那么你并不懂 C/C++,不愿意折腾研究换语言,C语言或许更好一点。

我也只不过是熟悉、了解 C/C++ 这门语言的一个水平,谈不上精通,毕竟又有谁轻言精通?可能只有造假、骗子才会轻言精通把。

C 语言一般不需要这么深入的研究,因为 C语言编译出现BUG的可能性很低,但放到 C/C++ 就不一样了,这也是为什么 C++ 对人的综合素质,要求很高的缘故。

否则怎会有只有玩 C++ 的人,才是一名真正的开发人员的典故,不是。

OK,当我们确认了,因为 C/C++  编译器优化导致的编译器BUG问题函数点时:

我们就需要编写下述的编译器指令,要求编译器来禁用优化,或者调整优化级别。

但这需要评估是否可以通过减少优化级别来解决该问题,某些情况下并不需要减少优化级别,只需要调整该函数、及关联调用方、被调用方函数来解决。【取决于人们是否需要极致调效】

例如:(下述)

1、在CLANG之中禁用优化

2、在GCC 7.5 <= 编译器版本之中,使用 /O1优化

3、在GCC 7.5 > 编译器版本之中,禁用优化

4、在VC++ 之中使用/O1优化(gsyb2为/O1优化级别编译器参数)

所以只需要在找到被编译器优化函数会导致崩溃BUG的真正元凶(问题点函数):

在函数头声明:

#if _WIN32
#pragma optimize("", off)
#pragma optimize("gsyb2", on) /* /O1 = /Og /Os /Oy /Ob2 /GF /Gy */
#else
#pragma GCC push_options
// TRANSMISSIONO1 compiler macros are defined to perform O1 optimizations, 
// Otherwise gcc compiler version If <= 7.5.X, 
// The O1 optimization will also be applied, 
// And the other cases will not be optimized, 
// Because this will cause the program to crash, 
// Which is a fatal BUG caused by the gcc compiler optimization. 
// Higher-version compilers should not optimize the code for gcc compiling this section.
#if __clang__
#pragma clang optimize off
#elif (TRANSMISSION_O1) || (__GNUC__ < 7) || (__GNUC__ == 7 && __GNUC_MINOR__ <= 5) /* __GNUC_PATCHLEVEL__ */
#pragma GCC optimize("O1")
#else
#pragma GCC optimize("O0")
#endif
#endif

 在函数尾声明:

#if _WIN32
#pragma optimize("", on)
#else
#if __clang__
#pragma clang optimize on
#else
#pragma GCC pop_options
#endif
#endif

即可解决编译器优化导致的程序致命性问题。

这篇关于如何解决 C/C++ 编译器优化导致的编译BUG(程序崩溃)支援VC++/CLANG/GCC的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/761687

相关文章

解决RocketMQ的幂等性问题

《解决RocketMQ的幂等性问题》重复消费因调用链路长、消息发送超时或消费者故障导致,通过生产者消息查询、Redis缓存及消费者唯一主键可以确保幂等性,避免重复处理,本文主要介绍了解决RocketM... 目录造成重复消费的原因解决方法生产者端消费者端代码实现造成重复消费的原因当系统的调用链路比较长的时

C++11范围for初始化列表auto decltype详解

《C++11范围for初始化列表autodecltype详解》C++11引入auto类型推导、decltype类型推断、统一列表初始化、范围for循环及智能指针,提升代码简洁性、类型安全与资源管理效... 目录C++11新特性1. 自动类型推导auto1.1 基本语法2. decltype3. 列表初始化3

深度解析Nginx日志分析与499状态码问题解决

《深度解析Nginx日志分析与499状态码问题解决》在Web服务器运维和性能优化过程中,Nginx日志是排查问题的重要依据,本文将围绕Nginx日志分析、499状态码的成因、排查方法及解决方案展开讨论... 目录前言1. Nginx日志基础1.1 Nginx日志存放位置1.2 Nginx日志格式2. 499

SpringBoot监控API请求耗时的6中解决解决方案

《SpringBoot监控API请求耗时的6中解决解决方案》本文介绍SpringBoot中记录API请求耗时的6种方案,包括手动埋点、AOP切面、拦截器、Filter、事件监听、Micrometer+... 目录1. 简介2.实战案例2.1 手动记录2.2 自定义AOP记录2.3 拦截器技术2.4 使用Fi

C++11右值引用与Lambda表达式的使用

《C++11右值引用与Lambda表达式的使用》C++11引入右值引用,实现移动语义提升性能,支持资源转移与完美转发;同时引入Lambda表达式,简化匿名函数定义,通过捕获列表和参数列表灵活处理变量... 目录C++11新特性右值引用和移动语义左值 / 右值常见的左值和右值移动语义移动构造函数移动复制运算符

kkFileView启动报错:报错2003端口占用的问题及解决

《kkFileView启动报错:报错2003端口占用的问题及解决》kkFileView启动报错因office组件2003端口未关闭,解决:查杀占用端口的进程,终止Java进程,使用shutdown.s... 目录原因解决总结kkFileViewjavascript启动报错启动office组件失败,请检查of

SQL Server安装时候没有中文选项的解决方法

《SQLServer安装时候没有中文选项的解决方法》用户安装SQLServer时界面全英文,无中文选项,通过修改安装设置中的国家或地区为中文中国,重启安装程序后界面恢复中文,解决了问题,对SQLSe... 你是不是在安装SQL Server时候发现安装界面和别人不同,并且无论如何都没有中文选项?这个问题也

C++中detach的作用、使用场景及注意事项

《C++中detach的作用、使用场景及注意事项》关于C++中的detach,它主要涉及多线程编程中的线程管理,理解detach的作用、使用场景以及注意事项,对于写出高效、安全的多线程程序至关重要,下... 目录一、什么是join()?它的作用是什么?类比一下:二、join()的作用总结三、join()怎么

java内存泄漏排查过程及解决

《java内存泄漏排查过程及解决》公司某服务内存持续增长,疑似内存泄漏,未触发OOM,排查方法包括检查JVM配置、分析GC执行状态、导出堆内存快照并用IDEAProfiler工具定位大对象及代码... 目录内存泄漏内存问题排查1.查看JVM内存配置2.分析gc是否正常执行3.导出 dump 各种工具分析4.

Go语言编译环境设置教程

《Go语言编译环境设置教程》Go语言支持高并发(goroutine)、自动垃圾回收,编译为跨平台二进制文件,云原生兼容且社区活跃,开发便捷,内置测试与vet工具辅助检测错误,依赖模块化管理,提升开发效... 目录Go语言优势下载 Go  配置编译环境配置 GOPROXYIDE 设置(VS Code)一些基本