一个局部变量分配的问题
# include <iostream>
using namespace std;
int func1()
{
int n = 12345;
return n;
}
int func2()
{
int m;
return m;
}
int main()
{
func1();
cout << func2() << endl;
int ( *g1 )( ) = func1;
int ( *g2 )( ) = func2;
cout << "The address of func1():" << &g1 << endl;
// prinf the address of func1()
cout << "The address of func2():" << &g2 << endl;
system( "pause" );
}
在dev-c++下输出如下:
12345
The address of func1():0x22ff74
The address of func2():0x22ff70
Press any key to continue . . .
问题是:函数func1()和func2()的结构相同,但是它们分配的地址不一样,m和n分配的地址怎么会一样呢?
问题点数:20、回复次数:14Top
1 楼XBox360(菜)(鸟)回复于 2005-08-04 18:48:18 得分 0
的确很神奇
mark一个Top
2 楼hafent(大海扬波)回复于 2005-08-04 18:50:05 得分 0
我在VC6下面试了,第一个输出是-858993460Top
3 楼sankt(宠辱不惊,看庭前花开花落;去留无意,望天空云卷云舒.)回复于 2005-08-04 18:59:20 得分 0
猜想:
编译器的原因,它把两个变量优化成一个了.Top
4 楼LoveYouJustOneDay(哈哈)回复于 2005-08-04 19:06:22 得分 3
m和n都是栈里分配的
栈的数据没有被破坏当然是这样的了Top
5 楼snowbirdfly(专心搞好嵌入式~~~)回复于 2005-08-04 21:18:23 得分 2
VC6下:-858993460
The address of func1():0012FF7C
The address of func2():0012FF78
函数入口地址是应该不同啊!Top
6 楼qhfu(改个名字)回复于 2005-08-04 21:39:53 得分 0
我也觉得是编译器的原因!Top
7 楼lxk_cool()回复于 2005-08-04 22:55:26 得分 0
不懂,学习一下Top
8 楼mayflowers(黯然神伤)回复于 2005-08-04 23:08:35 得分 3
...先多看看书吧,关于函数调用,关于栈,关于局部变量初始化。
只说一句:
cout << "The address of func1():" << &g1 << endl;
打印的是g1的地址,不是func1的入口地址。
要打印可以用:
cout << g1 << endl;
或
cout << func1 << endl。Top
9 楼zenny_chen(ACE Intercessor)回复于 2005-08-04 23:18:21 得分 2
这可能是dev-C++的编译器对函数中的局部变量做了优化分配。因为当func1调用结束后,m就会被释放。这样
m和n居于同一个地址并不会有影像。你可以试试将func2嵌入到func1中,结果会如何。
另外,你下面输出的是g1和g2它们自己所处的地址而不是它们所指函数的地址。要看它们所指函数的地址应该将&去掉。
Top
10 楼jiajun2001(Jagen(嘉俊))回复于 2005-08-04 23:31:43 得分 10
我来帮你解答!
这是由于局部变量的存储位置是堆栈,与具体的函数所在的地址没有关系。
我们知道,i386体系的堆栈都是向下增长的。那么在C/C++语言中,函数的参数以及局部变量都存储在这个堆栈中的。一个应用程序启动时,操作系统就会为他分配一个堆栈地址空间,由esp寄存器维护。如果创建一个现程后,操作系统还会为新的显程分配堆栈地址空间,也是由esp寄存器维护。在进行任务切换时,修改esp寄存器就可以。不过这不是我们要讨论的主要问题,仅作为一个开头,让大家对堆栈有一个印象。
向楼主提出的这个问题,很有特点。他的两个函数型除名称外,其他都一模一样。那么,它们在的内部实现也就是差不多一模一样了。它们产生的对应的汇编代码就差不多是下面这样:
func1:
push ebp
sub esp, 4 ->这里分配局部变量n
mov ebp, esp
mov [ebp+4],123456 ->为n附初值,记住堆栈是向下增长的
mov eax, [ebp+4] ->返回值放在eax中传回
add esp, 4 ->恢复堆栈
pop ebp
ret
func2:
push ebp
sub esp, 4
mov eax, [ebp+4]
add esp, 4
pop ebp
ret
那么调用它们的汇编代码基本如下:
call func1
call func2
由于func1已经将12345移到堆栈所使用的内存中了,在两次函数调用期间也没有对堆栈进行过操作,而局部变量m和n恰好在堆栈的同一位置,因此,m和n所分配的地址相同,内容也相同,这就是为什么没有初始化的局部变量值不确定的原因。
而对于VC而言,他们在debug模式下,都会把未初始化的变量自动初始化为0xcccccccc,他们实际上是8个汇编代码int 3的机器码,VC这样做主要是为了调试。
因此func2的汇编代码在VC下可能就是:
func2:
push ebp
sub esp, 4
mov [ebp+4], 0xcccccccc
mov eax, [ebp+4]
add esp, 4
pop ebp
ret
这样,程序的输出结果肯定就变了,如果你使用Release方式编译的话,肯定得到的是楼主的结果。
Dev-cpp默认的时候就是Release编译。
这不属于编译器的优化起的作用。
Top
11 楼waynahu(FIRE_BIRD-->涅磐)回复于 2005-08-05 08:54:00 得分 0
函数func1()和func2()的结构相同,但是它们分配的地址不一样,m和n分配的地址怎么会一样呢?
???????????????
什么“m和n分配的地址怎么会一样呢”,不懂。请问你从程序的哪个地方发现的啊?Top
12 楼jiajun2001(Jagen(嘉俊))回复于 2005-08-05 09:21:02 得分 0
m和n分配的地址确实是相同的,看我上面的解释Top
13 楼XBox360(菜)(鸟)回复于 2005-08-05 10:28:01 得分 0
但是在VC中结果不一样
-858993460Top
14 楼jiajun2001(Jagen(嘉俊))回复于 2005-08-05 21:12:59 得分 0
我上面也解释了,你把0xcccccccc转变成10进制,你看看是不是-858993460!
你干脆把这两个变量的地址输出出来,你看看,肯定是一样的!Top




