烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫
是debug中未初始化的栈变量
屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯
是debug中未初始化的堆变量
0xcc 16进制数,相当于十进制的204
未初始化的变量
DEBUG模式下运行时,未初始化的变量会被系统赋初值为0xCC
未初始化的变量会被系统赋初值为0xCC,超过了ASCII码0-127这个范围,因此这个“字符串”被系统当成了宽字符组成的字符串,即两个字节数据组成一个字符,而0xCCCC表示的宽字符正好是乱码中的那个“烫”字。
烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫
是debug中未初始化的栈变量
屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯
是debug中未初始化的堆变量
浅析"烫烫烫烫"是怎么来的
浅析"烫烫烫烫"是怎么来的
在用VC写代码时,经常会遇到在栈中申请空间的并且没有被初始化的字符数组就会显示"烫烫烫烫。。。",虽然是知道编译器对栈中没有初始化的数据会进行默认的初始化工作,但是一直不得要领,在拜读《程序员的自我修养》的时候有所收获,还挺有意思的,写出来和大家分享。
代码很简单,就是在栈中申请了一个大小为4个字节的字符数组。
- int main( void )
- {
- char x[4];
- return 0;
- }
用断点查看X的值,可以发现,“烫烫”出现了:
x 0x0012ff60 "烫烫烫烫?" char [4]
查看反汇编:
- 1: int main( void )
- 2: {
- 004113A0 55 push ebp
- 004113A1 8B EC mov ebp,esp
- 004113A3 81 EC CC 00 00 00 sub esp,0CCh
- 004113A9 53 push ebx
- 004113AA 56 push esi
- 004113AB 57 push edi
- 004113AC 8D BD 34 FF FF FF lea edi,[ebp-0CCh]
- 004113B2 B9 33 00 00 00 mov ecx,33h
- 004113B7 B8 CC CC CC CC mov eax,0CCCCCCCCh
- 004113BC F3 AB rep stos dword ptr es:[edi]
- 3: char x[4];
- 4: return 0;
- 004113BE 33 C0 xor eax,eax
- 5: }
简单解释一下关键句的含义:
004113AC 8D BD 34 FF FF FF lea edi,[ebp-0CCh]
将获得的0CCh大小的栈空间首地址赋给edi
004113B2 B9 33 00 00 00 mov ecx,33h
rep的循环次数为33h
004113B7 B8 CC CC CC CC mov eax,0CCCCCCCCh
eax = 0CCCCCCCCh
004113BC F3 AB rep stos dword ptr es:[edi]
将栈空间的33H个双字节赋值为0CCCCCCCCh
而0xcccc用汉语表示刚好就是“烫”
oxcc正好是中断int 3的指令 起到保护作用
为什么DEBUG的时候,内存里都是“烫烫烫烫烫烫烫烫烫……”呢?
是内存太热了吗?哈哈,当然不是。。
以下转自CSDN
在 Debug 模式下会自动加上 /GZ 编译选项,它可以帮助捕获内存错误。
/GZ 选项会做以下这些事
(1) 初始化内存和变量。包括用 0xCC 初始化所有自动变量,0xCD ( Cleared Data ) 初始化堆中分配的内存(即动态分配的内存,例如 new ),0xDD ( Dead Data ) 填充已被释放的堆内存(例如 delete ),0xFD( deFencde Data ) 初始化受保护的内存(debug 版在动态分配内存的前后加入保护内存以防止越界访问),其中括号中的词是微软建议的助记词。这样做的好处是这些值都很大,作为指针是不可能的(而且 32 位系统中指针很少是奇数值,在有些系统中奇数的指针会产生运行时错误),作为数值也很少遇到,而且这些值也很容易辨认,因此这很有利于在 Debug 版中发现 Release 版才会遇到的错误。要特别注意的是,很多人认为编译器会用 0 来初始化变量,这是错误的(而且这样很不利于查找错误)。
(2) 通过函数指针调用函数时,会通过检查栈指针验证函数调用的匹配性。(防止原形不匹配)
(3) 函数返回前检查栈指针,确认未被修改。(防止越界访问和原形不匹配,与第二项合在一起可大致模拟帧指针省略FPO)
“烫”字的MBCS编码为“CCCC”,而用 /GZ 选项对自动变量会用“0xCC”初始化,连续的“0xCC”将被误读成“烫”字符。
例子:
char strBusID[5 ];
memset(strBusID,0,5 ); // 把5个字节全部清0,最关键的就是把strBusID[4]置为'/0'
char* filebuffer ="x10001192.168.100.224asdfghijklmnopqrstuvw";
memcpy(strBusID,(filebuffer +2),4);
char s[]这样的字符串实质上是数组,它是依靠'/0'来标记字符串结尾的。
如果0001之后没有'/0',他就会把后续内存里的内容取出来,直到遇到一个'/0'为止。
注意区别'/0'和'0'。'/0'对应ascii的0,'0'对应ascii码的48。
DEBUG模式下运行时,未初始化的变量会被系统赋初值为0xCC ,超过了ASCII码0-127这个范围,因此这个“字符串”被系统当成了宽字符组成的字符串,即两个字节数据组成一个字符,而0xCCCC表示的宽字符正好是乱码中的那个“烫”字。