张爱玲曾说过:“开发过程就是个玄学。”
有时候,程序在Debug模式下运行的好好的,一Release就crash了。
有时候,程序在Debug模式下崩溃了,Release模式下居然能正常运行。
以上这种情况,可能很多人都遇到过。
Ofast:打开可导致不符合IEEE浮点数等标准的性能优化选项。
具体介绍如下:
Og:如果是为了调试,该选项是比O0更好的选择,它会打开O1大部分优化标志,但是不会启用那些影响调试的标志:
O2:常见的Release级别,该选项下几乎执行了所有支持的优化选项,它增加了编译时间,提高了程序的运行速度,又额外打开了以下优化标志:
Os:打开了几乎所有的O2优化标志,除了那些经常会增加代码大小的优化标志:
Ofast:更加激进的编译选项,它不会严格遵循标准,在O3的优化基础上,它又开启了一些可能导致不符合IEEE浮点数等标准的性能优化选项,如- fast-math, -fallow-store-data-races等。
对于未初始化的变量,Debug模式下会默认对其进行初始化,而Release模式则不会,所以就有个常见的问题,局部变量未初始化时,Debug模式和Release模式表现有所不同。
bool func() {
bool found;
for (int i = 0; i < vec.size(); ++i) {
if (vec[i] == 3) {
found = true;
}
}
return found;
}
Debug模式下可能运行正常,但Release模式下可能会返回错误结果,因为found局部变量在Release模式下没有初始化。
Debug模式以32字节为单位分配内存,例如当申请24字节内存时,Release模式下是正常的分配24字节,Debug模式会分配32字节,多了8字节,所以有些数组越界问题在Debug模式下可以安全运行,Release模式下就会出问题。
Debug模式下可以使用assert,运行过程中有异常现象会及时crash,Release模式下模式下不会编译assert,遇到不期望的情况不会及时crash,稀里糊涂继续运行,到后期可能会产生奇奇怪怪的错误,不易调试,殊不知其实在很早之前就出现了问题。编译器在Debug模式下定义_DEBUG宏,Release模式下定义NDEBUG宏,预处理器就是根据对应宏来判断是否开启assert的。
数据溢出问题,在一个函数中,存在某些从未被使用的变量,且函数内存在数据溢出问题,在Debug模式下可能不会产生问题,因为不会对该变量进行优化,它在栈空间中还是占有几个字节,但Release模式下可能会出问题,Release模式下可能会优化掉此变量,栈空间相应变小,数据溢出就会导致栈内存损坏,有可能会产生奇奇怪怪的错误。
void func() {
char buffer[10];
int counter;
lstrcpy(buffer, "abcdefghik"); // 需要拷贝11字节
}
tips:不要将Debug库和Release库混合在一起,可能会出问题,至于为啥会出问题,知道的可在下方评论区留言,一般都是有两个目录,Debug目录和Release目录。
回到开篇提到的那两个问题:
程序在Debug模式下运行的好好的,Release模式下就crash了,怎么办?
可以尝试着找一找代码中的assert,看一下是否是assert导致的两种模式下的差异,从这个思路入手。
程序在Debug模式下会崩溃,Release模式下却正常运行,怎么办?
看一下代码中是否有未初始化的变量,是否有数组越界问题,从这个思路入手。
参考资料:
END
→点关注,不迷路←