很常见的一道笔试题,下边的这段代码,会输出什么?
返回并使用局部变量,这种方法肯定是错误的。但就这段代码本身,理论上又是可以正常工作的,因为堆栈中的"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 (生成最终的可执行文件)