本文仅适用于,有愿意、爱捣鼓的童靴。
因编译器优化导致编译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
即可解决编译器优化导致的程序致命性问题。