函数体内部的大括号离开以后大括号中的定义变量占用的内存会被编译器收回吗

zjtzlqr 2014-04-13 10:58:23
#include <stdio.h>

void dayin(int *p,int m)
{
int g = 3;
g++;
printf("%d",*p);
printf("%d",m);

}

int main(void)
{
int *a = NULL;

int b = 1;

if (1 == b)
{
int c = 5;
a = &c;
}

int f = 7;
int g = 9;

dayin(a,g);
}



相应的汇编代码
#include <stdio.h>

void dayin(int *p,int m)
{
00A613B0 push ebp
00A613B1 mov ebp,esp
00A613B3 sub esp,0CCh
00A613B9 push ebx
00A613BA push esi
00A613BB push edi
00A613BC lea edi,[ebp-0CCh]
00A613C2 mov ecx,33h
00A613C7 mov eax,0CCCCCCCCh
00A613CC rep stos dword ptr es:[edi]
int g = 3;
00A613CE mov dword ptr [g],3
g++;
00A613D5 mov eax,dword ptr [g]
00A613D8 add eax,1
00A613DB mov dword ptr [g],eax
printf("%d",*p);
00A613DE mov esi,esp
00A613E0 mov eax,dword ptr [p]
00A613E3 mov ecx,dword ptr [eax]
00A613E5 push ecx
00A613E6 push offset string "%d" (0A6573Ch)
00A613EB call dword ptr [__imp__printf (0A682BCh)]
00A613F1 add esp,8
00A613F4 cmp esi,esp
00A613F6 call @ILT+315(__RTC_CheckEsp) (0A61140h)
printf("%d",m);
00A613FB mov esi,esp
00A613FD mov eax,dword ptr [m]
00A61400 push eax
00A61401 push offset string "%d" (0A6573Ch)
00A61406 call dword ptr [__imp__printf (0A682BCh)]
00A6140C add esp,8
00A6140F cmp esi,esp
00A61411 call @ILT+315(__RTC_CheckEsp) (0A61140h)

}
00A61416 pop edi
00A61417 pop esi
00A61418 pop ebx
00A61419 add esp,0CCh
00A6141F cmp ebp,esp
00A61421 call @ILT+315(__RTC_CheckEsp) (0A61140h)
00A61426 mov esp,ebp
00A61428 pop ebp
00A61429 ret
--- 无源文件 -----------------------------------------------------------------------
00A6142A int 3
00A6142B int 3
00A6142C int 3
00A6142D int 3
00A6142E int 3
00A6142F int 3
00A61430 int 3
00A61431 int 3
00A61432 int 3
00A61433 int 3
00A61434 int 3
00A61435 int 3
00A61436 int 3
00A61437 int 3
00A61438 int 3
00A61439 int 3
00A6143A int 3
00A6143B int 3
00A6143C int 3
00A6143D int 3
00A6143E int 3
00A6143F int 3
00A61440 int 3
00A61441 int 3
00A61442 int 3
00A61443 int 3
00A61444 int 3
00A61445 int 3
00A61446 int 3
00A61447 int 3
00A61448 int 3
00A61449 int 3
00A6144A int 3
00A6144B int 3
00A6144C int 3
00A6144D int 3
00A6144E int 3
00A6144F int 3
--- f:\c++\exercise\exercise\exercise\main.cpp ---------------------------------

int main(void)
{
00A61450 push ebp
00A61451 mov ebp,esp
00A61453 sub esp,0FCh
00A61459 push ebx
00A6145A push esi
00A6145B push edi
00A6145C lea edi,[ebp-0FCh]
00A61462 mov ecx,3Fh
00A61467 mov eax,0CCCCCCCCh
00A6146C rep stos dword ptr es:[edi]
int *a = NULL;
00A6146E mov dword ptr [a],0

int b = 1;
00A61475 mov dword ptr [b],1

if (1 == b)
00A6147C cmp dword ptr [b],1
00A61480 jne main+3Fh (0A6148Fh)
{
int c = 5;
00A61482 mov dword ptr [c],5
a = &c;
00A61489 lea eax,[c]
00A6148C mov dword ptr [a],eax
}

int f = 7;
00A6148F mov dword ptr [f],7
int g = 9;
00A61496 mov dword ptr [g],9

dayin(a,g);
00A6149D mov eax,dword ptr [g]
00A614A0 push eax
00A614A1 mov ecx,dword ptr [a]
00A614A4 push ecx
00A614A5 call dayin (0A610E1h)
00A614AA add esp,8
}
00A614AD xor eax,eax
00A614AF push edx
00A614B0 mov ecx,ebp
00A614B2 push eax
00A614B3 lea edx,[ (0A614D4h)]
00A614B9 call @ILT+130(@_RTC_CheckStackVars@8) (0A61087h)
00A614BE pop eax
00A614BF pop edx
00A614C0 pop edi
00A614C1 pop esi
00A614C2 pop ebx
00A614C3 add esp,0FCh
00A614C9 cmp ebp,esp
00A614CB call @ILT+315(__RTC_CheckEsp) (0A61140h)
00A614D0 mov esp,ebp
00A614D2 pop ebp
00A614D3 ret
00A614D4 db 01h
00A614D5 db 00h
00A614D6 db 00h
00A614D7 db 00h
00A614D8 db dch
00A614D9 db 14h
00A614DA db a6h
00A614DB db 00h
00A614DC db e0h
00A614DD db ffh
00A614DE db ffh
00A614DF db ffh
00A614E0 db 04h
00A614E1 db 00h
00A614E2 db 00h
00A614E3 db 00h
00A614E4 db e8h
00A614E5 db 14h
00A614E6 db a6h
00A614E7 db 00h
00A614E8 db 63h
00A614E9 db 00h



两个问题
1:
printf("%d",*p);
00A613DE mov esi,esp
00A613E0 mov eax,dword ptr [p]
00A613E3 mov ecx,dword ptr [eax]
00A613E5 push ecx
00A613E6 push offset string "%d" (0A6573Ch)
00A613EB call dword ptr [__imp__printf (0A682BCh)]
00A613F1 add esp,8
00A613F4 cmp esi,esp
00A613F6 call @ILT+315(__RTC_CheckEsp) (0A61140h)



00A613E0 mov eax,dword ptr [p]

网上都说mov eax,dword ptr [p]的意思是把把p指向的内容复制给寄存器eax,为什么实际执行了这句话的结果只是把p这个地址复制给寄存器
而下面同样的汇编00A613E3 mov ecx,dword ptr [eax] 却是把eax寄存器指向的内容也就是5复制给寄存器eax


问题2、为什么
if (1 == b)
{
int c = 5;
a = &c;
}

大括号中定义的变量c在离开}符号以后c占用的内存会被编译器收回吗? 一个函数中离开函数体会收回。不知道函数体中包含的某个大括号是不是也是这样









...全文
301 18 打赏 收藏 转发到动态 举报
写回复
用AI写文章
18 条回复
切换为时间正序
请发表友善的回复…
发表回复
赵4老师 2014-04-15
  • 打赏
  • 举报
回复
引用 15 楼 lin5161678 的回复:
有没有回收 不重要 重要的是要明白 块结束的时候 变量c 的生命期也结束了 a指向一个无效对象 是野指针
对于一个处心积虑想要从内存中获取敏感信息的黑客来说,有没有回收|清除|覆盖很重要!
赵4老师 2014-04-15
  • 打赏
  • 举报
回复
其实电脑开机后物理内存的每个字节都是可读写的,区别仅在于操作系统内存管理模块在你读写时是否能发现并是否采取相应动作而已。操作系统管理内存的粒度不是字节而是页,一页通常为4KB。
lin5161678 2014-04-15
  • 打赏
  • 举报
回复
有没有回收 不重要 重要的是要明白 块结束的时候 变量c 的生命期也结束了 a指向一个无效对象 是野指针
如此美丽的你 2014-04-15
  • 打赏
  • 举报
回复
答案:会收回 详解:这里的内存是栈内存,而非堆内存。 堆内存的开辟(new malloc)是要手动释放(delete free)的 栈就不一样了,栈是增长的,声明一个局部变量无非是栈增长一点,生命期结束后栈回缩,就相当于回收内存了。接下来栈再增长的话就覆盖先前的位置了
zhuobattle 2014-04-15
  • 打赏
  • 举报
回复
编译器如果发现大括号内栈分配内存并不多,就没必要回收。 你可以试下如果分配很多一个栈,编译器编译好的代码可能就会有pop指令
  • 打赏
  • 举报
回复
答案:会收回 详解:这里的内存是栈内存,而非堆内存。 堆内存的开辟(new malloc)是要手动释放(delete free)的 栈就不一样了,栈是增长的,声明一个局部变量无非是栈增长一点,生命期结束后栈回缩,就相当于回收内存了。接下来栈再增长的话就覆盖先前的位置了
PDD123 2014-04-15
  • 打赏
  • 举报
回复
所有的局部变量都是在栈或者寄存器中,出了大括号之后,大括号中变量所在位置就不受保护了,有可能被其他的指令修改。 就10楼中的例子,c这个变量,在if语句的括号中被赋予5,出了大括号之后,其位置就可能被printf函数的一些指令修改,printf在输出其值的时候,就不一定会输出5了。
lm_whales 2014-04-15
  • 打赏
  • 举报
回复
第一个问题,p是个指针,值即它的内容,就是它所指向的对象的地址
00A613E0  mov eax,dword ptr [p] ;//dword ptr [p] 是指针变量p 的的内容,
;//就是指针的值
 ; // 对于符号地址p, mov eax,dword ptr [p] 等价于mov eax,dword ptr p  
00A613E3  mov ecx,dword ptr[eax];//指针p指向的内容,赋值给ecx;eax当作指针寄存器使用。
00A613E5  push ecx                          ;//ecx内容 压栈 ,实际就是push *p
00A613E6  push offset string "%d" (0A6573Ch)  ;//格式化串(地址)压栈 
00A613EB  call dword ptr [__imp__printf (0A682BCh)] ;// 调用 printf
00A613F1  add esp,8                            //清栈   
zjtzlqr 2014-04-14
  • 打赏
  • 举报
回复
我想知道的是汇编代码中应该是没有{}的 是不是碰到ret就会将之前定义的局部变量的内存释放
赵4老师 2014-04-14
  • 打赏
  • 举报
回复
不要混淆栈和堆内存的分配释放
赵4老师 2014-04-14
  • 打赏
  • 举报
回复
计算机组成原理→DOS命令→汇编语言→C语言(不包括C++)、代码书写规范→数据结构、编译原理、操作系统→计算机网络、数据库原理、正则表达式→其它语言(包括C++)、架构…… 对学习编程者的忠告: 眼过千遍不如手过一遍! 书看千行不如手敲一行! 手敲千行不如单步一行! 单步源代码千行不如单步对应汇编一行! 单步类的实例“构造”或“复制”或“作为函数参数”或“作为函数返回值返回”或“参加各种运算”或“退出作用域”的语句对应的汇编代码几步后,就会来到该类的“构造函数”或“复制构造函数”或“运算符重载”或“析构函数”对应的C/C++源代码处。 VC调试时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化,这样过一遍不就啥都明白了吗。 对VC来说,所谓‘调试时’就是编译连接通过以后,按F10或F11键单步执行一步以后的时候,或者在某行按F9设了断点后按F5执行停在该断点处的时候。 (Turbo C或Borland C用Turbo Debugger调试,Linux或Unix下用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。)
M阳光 2014-04-14
  • 打赏
  • 举报
回复
至于问题2,: 个人感觉没必要从汇编上分析:
#include <stdio.h>
int main()
{
	int *a = NULL;
	int b = 1;

	if (1 == b)
	{
		int c = 5;
		a = &c;		
	}
	printf("%d\n",*a);
	int f = 7;
	int g = 9;

	return 0;
}
M阳光 2014-04-14
  • 打赏
  • 举报
回复
问题1: p是一个指针变量,里面储存的是一个地址,p所指向内容的地址。但是,一个指针,它也要占空间,对吧~,汇编需要从内存中找到p所在的位置。。So,。。[p]实际上就是p里面存储的东西。 所以 mov eax,dword ptr [p] 是把p里面储存的地址赋给eax,. 然后,ecx,dword ptr [eax] 才真正访问到了p指向的内容。 唔。。我语文不好。。~
lpcads 2014-04-14
  • 打赏
  • 举报
回复
引用 5 楼 zjtzlqr 的回复:
我想知道的是汇编代码中应该是没有{}的 是不是碰到ret就会将之前定义的局部变量的内存释放
请搜索 add esp,8 add esp,0FCh 用途
zjtzlqr 2014-04-13
  • 打赏
  • 举报
回复
dayin(a,g);这个函数使用a指向的内容有没有可能已经被其他变量使用了,变量c是在{}中定义的 已经离开{}了 if (1 == b) { int c = 5; a = &c; }
derekrose 2014-04-13
  • 打赏
  • 举报
回复
引用 2 楼 zjtzlqr 的回复:
[quote=引用 1 楼 derekrose 的回复:] 其实编译器不是标准,而且编译器太多种了
用的vs2008,主要想看明白函数调用的实际过程[/quote] 但是你所说的大括号 并不是函数调用呀 如果你想知道编译器是如何看待大括号这个分隔符号的话,你可以去搜一搜相关的编译中的分隔符分析 或者你自己想想如果你要写一个编译器 当你scan到一个大括号 你要怎么做
zjtzlqr 2014-04-13
  • 打赏
  • 举报
回复
引用 1 楼 derekrose 的回复:
其实编译器不是标准,而且编译器太多种了
用的vs2008,主要想看明白函数调用的实际过程
derekrose 2014-04-13
  • 打赏
  • 举报
回复
其实编译器不是标准,而且编译器太多种了

69,364

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧