#include <stdio.h> #include <stdlib.h> #include <string.h> void function(int *i) { int *_prev_int = (int *) ((long unsigned int) i - sizeof(int)) ; printf("%d\n",*_prev_int ); } void main(void) { int x = 152; int y = 234; function(&y); }
看看我在做什么?假设sizeof(int)为4:我在传递的指针后面看了4个字节,因为它会读取调用者堆栈中int y之前的4个字节.
它没有打印152.奇怪的是当我看下4个字节时:
int *_prev_int = (int *) ((long unsigned int) i + sizeof(int)) ;
解决方法
有些变量甚至不在堆栈上(例如,因为它们只是保存在某些寄存器中,或者因为编译器通过内联,常量折叠等优化它们 – 例如.).
顺便说一下,你可以有一些假设的C实现,它不使用任何堆栈(即使我不能命名这样的实现).
要了解有关堆栈的更多信息:
>阅读call stacks,tail calls,threads和continuations上的wikipage
>熟悉您的计算机architecture& instruction set(例如x86)& ABI,然后……
>让您的编译器显示汇编代码和/或一些中间编译器表示.如果使用GCC,使用gcc -S -fverbose-asm编译一些简单的代码(在编译foo.c时获取汇编代码foo.s)并尝试几个优化级别(至少-O0,-O1,-O2 …. ).还可以尝试-fdump-tree-all选项(它会转储数百个文件,显示源代码的编译器的内部表示).请注意,GCC还提供return address builtins
>在garbage collection can be faster than stack allocation阅读Appel的旧论文,并了解garbage collection技术(因为他们经常需要检查并可能更改调用堆栈帧内的一些指针).要了解有关GC的更多信息,请阅读GC handbook.
遗憾的是,我不知道在语言级别可以访问调用堆栈的低级语言(如C,D,Rust,C,Go,…).这就是为C编写垃圾收集器很困难的原因(因为GC-s需要扫描调用堆栈指针)…但是请参阅Boehm’s conservative GC以获得非常实用和实用的解决方案.