【发布时间】:2014-09-21 18:25:00
【问题描述】:
考虑下面的代码..
#include <vector>
std::basic_string<char> sBasicString = "basic_string";
char* buffer = new char[1000];
for (size_t i = 0 ; i < sBasicString.size() ; ++i)
{
char c;
c = sBasicString[i];
buffer[i] = c;
}
(请忽略内存泄漏 - 这无关紧要)
我在 VS2012 64 位版本和调试(默认配置)中编译它。
当我在调试模式下运行调试器时,我可以按预期观察sBasicString 和buffer 变量(查询它们的值等...)
但是当我在发布模式下运行调试器时,我仍然可以看到sBasicString,但看不到buffer。
为什么?
由于发布模式的优化设置为“完全优化”(默认值),“生成调试信息”设置为“是” - 我希望这两个变量都可以观看或不观看。
编辑
尝试添加 buffer 变量的正确用法(避免编译器优化) - 我仍然得到相同的行为。
EDIT 2添加Release模式编译的64位反汇编输出
int main()
{
000000013F091000 mov rax,rsp
000000013F091003 push rbx
000000013F091004 sub rsp,50h
000000013F091008 mov qword ptr [rax-38h],0FFFFFFFFFFFFFFFEh
std::basic_string<char> sBasicString = "basic_string";
000000013F091010 xor ebx,ebx
000000013F091012 mov qword ptr [rax-20h],rbx
000000013F091016 mov qword ptr [rax-18h],rbx
000000013F09101A mov qword ptr [rax-18h],0Fh
000000013F091022 mov qword ptr [rax-20h],rbx
000000013F091026 mov byte ptr [rax-30h],bl
000000013F091029 lea r8d,[rbx+0Ch]
000000013F09102D lea rdx,[__xi_z+40h (013F093238h)]
000000013F091034 lea rcx,[rax-30h]
000000013F091038 call std::basic_string<char,std::char_traits<char>,std::allocator<char> >::assign (013F0916A0h)
000000013F09103D nop
char* buffer = new char[1000];
000000013F09103E mov ecx,3E8h
000000013F091043 call operator new[] (013F091AD8h)
for (size_t i = 0 ; i < sBasicString.size() ; ++i)
000000013F091048 mov edx,ebx
000000013F09104A cmp qword ptr [rsp+38h],rbx
000000013F09104F jbe main+73h (013F091073h)
{
char c;
c = sBasicString[i];
000000013F091051 lea rcx,[sBasicString]
000000013F091056 cmp qword ptr [rsp+40h],10h
000000013F09105C cmovae rcx,qword ptr [sBasicString]
buffer[i] = c;
000000013F091062 movzx ecx,byte ptr [rcx+rdx]
buffer[i] = c;
000000013F091066 mov byte ptr [rdx+rax],cl
for (size_t i = 0 ; i < sBasicString.size() ; ++i)
000000013F091069 inc rdx
000000013F09106C cmp rdx,qword ptr [rsp+38h]
000000013F091071 jb main+51h (013F091051h)
}
std::cout << buffer << std::endl;
000000013F091073 mov rdx,rax
000000013F091076 mov rcx,qword ptr [__imp_std::cout (013F093068h)]
000000013F09107D call std::operator<<<std::char_traits<char> > (013F0910C0h)
000000013F091082 mov rcx,rax
000000013F091085 mov rdx,qword ptr [__imp_std::endl (013F093060h)]
000000013F09108C call qword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (013F093098h)]
000000013F091092 nop
return 0;
000000013F091093 cmp qword ptr [rsp+40h],10h
000000013F091099 jb main+0A5h (013F0910A5h)
000000013F09109B mov rcx,qword ptr [sBasicString]
000000013F0910A0 call operator delete (013F091AEAh)
000000013F0910A5 mov qword ptr [rsp+40h],0Fh
000000013F0910AE mov qword ptr [rsp+38h],rbx
000000013F0910B3 mov byte ptr [sBasicString],0
return 0;
000000013F0910B8 xor eax,eax
}
000000013F0910BA add rsp,50h
000000013F0910BE pop rbx
000000013F0910BF ret
EDIT 3添加32位反汇编输出
int main()
{
013B1000 push 0FFFFFFFFh
013B1002 push 13B2558h
013B1007 mov eax,dword ptr fs:[00000000h]
013B100D push eax
013B100E mov dword ptr fs:[0],esp
013B1015 sub esp,18h
013B1018 push esi
std::basic_string<char> sBasicString = "basic_string";
013B1019 push 0Ch
013B101B mov dword ptr [esp+18h],0
013B1023 mov dword ptr [esp+1Ch],0
013B102B push 13B3158h
013B1030 lea ecx,[esp+0Ch]
013B1034 mov dword ptr [esp+20h],0Fh
013B103C mov dword ptr [esp+1Ch],0
013B1044 mov byte ptr [esp+0Ch],0
013B1049 call std::basic_string<char,std::char_traits<char>,std::allocator<char> >::assign (013B17B0h)
013B104E mov dword ptr [esp+24h],0
char* buffer = new char[1000];
013B1056 push 3E8h
013B105B call operator new[] (013B1BD6h)
for (size_t i = 0 ; i < sBasicString.size() ; ++i)
013B1060 xor edx,edx
013B1062 add esp,4
013B1065 mov esi,eax
013B1067 cmp dword ptr [esp+14h],edx
013B106B jbe main+8Dh (013B108Dh)
for (size_t i = 0 ; i < sBasicString.size() ; ++i)
013B106D lea ecx,[ecx]
{
char c;
c = sBasicString[i];
013B1070 cmp dword ptr [esp+18h],10h
013B1075 lea ecx,[esp+4]
013B1079 cmovae ecx,dword ptr [esp+4]
for (size_t i = 0 ; i < sBasicString.size() ; ++i)
013B107E inc edx
buffer[i] = c;
013B107F mov al,byte ptr [ecx+edx-1]
013B1083 mov byte ptr [edx+esi-1],al
013B1087 cmp edx,dword ptr [esp+14h]
013B108B jb main+70h (013B1070h)
}
std::cout << buffer << std::endl;
013B108D push dword ptr ds:[13B3030h]
013B1093 push esi
013B1094 push dword ptr ds:[13B3034h]
013B109A call std::operator<<<std::char_traits<char> > (013B10F0h)
013B109F add esp,8
013B10A2 mov ecx,eax
013B10A4 call dword ptr ds:[13B3028h]
return 0;
013B10AA mov dword ptr [esp+24h],0FFFFFFFFh
013B10B2 cmp dword ptr [esp+18h],10h
013B10B7 pop esi
013B10B8 jb main+0C5h (013B10C5h)
013B10BA push dword ptr [esp]
013B10BD call operator delete (013B1BECh)
013B10C2 add esp,4
}
013B10C5 mov ecx,dword ptr [esp+18h]
return 0;
013B10C9 mov dword ptr [esp+14h],0Fh
013B10D1 mov dword ptr [esp+10h],0
013B10D9 mov byte ptr [esp],0
013B10DD xor eax,eax
}
013B10DF mov dword ptr fs:[0],ecx
013B10E6 add esp,24h
013B10E9 ret
【问题讨论】:
-
打开反汇编窗口以了解发生了什么。优化后的代码可能会将这个变量保留在 CPU 寄存器中,如果没有副作用,甚至可以删除整个代码片段。
-
可能只有这段代码的第一行保留在优化代码中。编译器不会删除类实例创建,因为它可能有副作用(例如火箭导弹)。尝试打印
buffer变量,看看会发生什么。 -
@AlexFarber - 检查我的编辑.. 我已经添加了
buffer变量的正确用法 - 仍然是同样的问题...... -
它可能在 CPU 寄存器中。理解这一点的唯一方法是查看汇编代码。您可以将汇编代码添加到问题中。更好的文字而不是截图,我们是程序员......
-
@AlexFarber - 已添加(抱歉,这篇文章太长了...)
标签: c++ debugging visual-studio-2012 stl internals