首页 > 代码库 > Visual Studio中Debug和Realse版本编译的结果不同

Visual Studio中Debug和Realse版本编译的结果不同

提要

最近用Visual Studio用的比较多,虽然慢了点,但是用着熟了感觉还是不错的,特别是2013里面的自动格式化代码,对我这种代码整洁强迫症患者真是莫大的帮助。

        但是,今天这个坑摸了差不多一天才出来。

环境:Win8.1 64bit  Visual Studio 2013 Qt5.3


Debug和Release版本的区别

Debug通常称为调试版本,它包含调试信息,并且不作任何优化,便于程序员调试程序。Release称为发布版本,它往往是进行了各种优化,使得程序在代码大小和运行速度上都是最优的,以便用户很好地使用。
Debug 和 Release 的真正秘密,在于一组编译选项。下面列出了分别针对二者的选项(当然除此之外还有其他一些,如/Fd /Fo,但区别并不重要,通常他们也不会引起 Release 版错误,在此不讨论)
Debug 版本

参数 含义
/MDd /MLd 或 /MTd 使用 Debug runtime library (调试版本的运行时刻函数库)
/Od 关闭优化开关
/D "_DEBUG" 相当于 #define _DEBUG,打开编译调试代码开关 (主要针对assert函数)
/ZI 创建 Edit and continue(编辑继续)数据库,这样在调试过程中如果修改了源代码不需重新编译
/GZ 可以帮助捕获内存错误
/Gm 打开最小化重链接开关, 减少链接时间

Release 版本

参数 含义
/MD /ML 或 /MT 使用发布版本的运行时刻函数库
/O1 或 /O2 优化开关,使程序最小或最快
/D "NDEBUG" 关闭条件编译调试代码开关 (即不编译assert函数)
/GF 合并重复的字符串, 并将字符串常量放到只读内存, 防止被修改

实际上,Debug 和 Release 并没有本质的界限,他们只是一组编译选项的集合,编译器只是按照预定的选项行动。事实上,我们甚至可以修改这些选项,从而得到优化过的调试版本或是带跟踪语句的发布版本。


运行结果不同的原因

debug跟release在初始化变量时所做的操作是不同的,debug是将每个字节位都赋成0xcc, 而release的赋值近似于随机。如果你的程序中的某个变量没被初始化就被引用,就很有可能出现异常:用作控制变量将导致流程导向不一致;用作数组下标将会使程序崩溃;更加可能是造成其他变量的不准确而引起其他的错误。所以在声明变量后马上对其初始化一个默认的值是最简单有效的办法,否则项目大了你找都没地方找。代码存在错误在debug方式下可能会忽略而不被察觉到。debug方式下数组越界也大多不会出错,在release中就暴露出来了,这个找起来就比较难了。


我遇到的问题

我这里遇到的一个问题是向内存申请一段内存来存储图片的像素值,按ARGB格式来存,即alpha通道1bit,red通道1bit,green通道1bit,blue通道1bit,则一个像素用4个自己来表示。

int length = uiCols * uiRows * bytesPerPixel;
unsigned char* m_arpBGRABuffers = new unsigned char[length];

//Save RGB value to buffer

最后存储在QImage中用来显示。

在Debug模式下,显示正确,但是有点灰,Release模式下什么都不显示。

最后定位到这个内存申请的位置,打印出内存的值,发现Debug模式下数组都被赋值为205,release模式下全部被赋值为0.

那么问题就来了,为神马是205!?

赶紧股沟 visual studio 205。

发现在cplusplus上,有个哥们遇到了类似的问题

struct COLOR
{
     unsigned char R;
     unsigned char G;
     unsigned char B;
};

int main()
{
     COLOR * color;
     color = new COLOR[5];
     cout << (int)color[3].G     //Default value of a color part....(right?)
     return 0;
}

The above, for SOME REASON, returns a value of 205.

205!? Why!?! Every R,G, and B of every COLOR in the array is set to 205!!!

Please give me an explanation...


他需要一个解释。


It is peculiarity of the Microsoft product(s):

if you declare a variable say for example:
int a then if it not initialised and you run the program then in the debugger it will show a value as follows:
char type will be 0xcc (decimal 204)
short will be 0xcccc
int will be 0xcccccccc
and so on.

If you create a variable/struct using new then if you run the program but have not initialised the variable/structure values
then you will see in the debugger:
char type will be 0xcd (decimal 205) ******
short will be 0xcdcd
int will be 0xcdcdcdcd
and so on.

An unitialised pointer will show as 0xcccccccc

I believe it really does put those values in - because if you try to cout an uninitialised variable and ignore the ‘Unitialised variable error dialog box‘
then you really will see those values on the screen.


这下明白了吧...


之所以release模式下不显示,因为alpha通道被赋值为0了,之所以debug模式下会有点灰,是因为alpha通道被赋值为205(完全不透明是255)。

解决方案,都赋初值:

int length = uiCols * uiRows * bytesPerPixel;
char * m_arpBGRABuffers = new unsigned char[length];

//Set ALL chinnal to 255
for (int i = 0; i < length; i++)
{
	m_arpBGRABuffers[iCamera][i] = 255;
}

这下整个世界都清晰了。对比一下:



debug模式下灰灰的图片



Release 模式下将alpha设为255后的图片


总结

所有类成员在构造函数中都赋好初值,不要相信和依赖编译器的行为。

动态申请内存的变量,申请完内存之后马上赋初值。

Visual Studio中Debug和Realse版本编译的结果不同