GetMemory问题

很常见的一道笔试题,下边的这段代码,会输出什么?

返回并使用局部变量,这种方法肯定是错误的。但就这段代码本身,理论上又是可以正常工作的,因为堆栈中的"Hello, world!",代码中并没有会对其产生破坏的地方

于是,很多人的答案都是能够正常输出"Hello, world!",包括我。而其中一部分人,回家真的试验一下,然后就郁闷了,因为结果并不符合预期

在我的机器上(fc11, gcc4.4.1),运行的结果是打印乱码

 

 

看看汇编代码

其中确实没有看到"Hello, world!"被修改

 

 

正百思不得其解,一个偶然机会,发现如果打印语句修改成:

printf("%c/n", p[0])

竟然打印"H"……怀疑printf有问题,于是修改如下:

输出结果:

Hell

ffffffb3 0 6c 0

 

 

第二,如果编译时加上-O2 (gcc -O2 getmem.c),同样能够正常输出,结果为:

Hell
Hello, world!
48 65 6c 6c

 

 

第三,如果在char msg[]前边加上另外一个大小合适的变量,msg也不会被破坏

通过试验,这个变量大小临界值在112字节,小于112字节,"Hello, world!"就会被破坏

另外,上述代码输出为:

Hell
Hello, world!
ffffffb3 0 e 0

说明在输出结果到标准输出后,printf还进一步占用了堆栈,并将"Hello, world!"破坏

 

 

由此,真相大白,"Hello, world!"是被printf修改的。应该是printf的局部变量,破坏了"Hello, world!"的内容

如果有耐心,可以跟踪进printf,看看到底什么时候修改的

 

 

附,生成汇编的方法(以源码为getmem.c为例)

gcc -S getmem.c (生成getmem.s,就是汇编代码)

as -o getmem.o -gstabs getmem.s

gcc getmem.o (生成最终的可执行文件)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值