由于C语言标准并没有将堆栈、程序区和堆定义为不同的区域,它们在不同的处理器架构、操作系统、加载器、链接器和编译器上的位置可能会有所不同,因此您无法以可移植的方式做到您想要的。尝试猜测指针指向的位置会破坏C语言所提供的抽象性,因此您可能不应该这样做。
尽管如此,在特定的环境中有一些编写代码的方法可以正确地猜测指针指向的位置。您可以通过检查现有对象的地址并寻找模式来实现这一点。考虑下面的程序。
#include <stdlib.h>
#include <stdio.h>
void
function()
{
int stack2;
printf("stack2: %15p\n", &stack2);
}
int
main(int argc, char *argv[])
{
int stack;
void *heap = malloc(1);
void *heap2 = malloc(1);
printf("program: %15p\n", main);
printf("heap: %15p\n", heap);
printf("heap2: %15p\n", heap2);
printf("stack: %15p\n", &stack);
function();
return 0;
}
通过检查其输出,您可以看到一种模式,例如在x64 Linux上的以下情况。
program: 0x400504
heap: 0x1675010
heap2: 0x1675030
stack: 0x7fff282c783c
stack2: 0x7fff6ae37afc
从上面,你可以确定(大概)堆增长从0x1675010开始,任何低于这个地址的东西都是程序代码(或静态数据,你没有提到),而栈是在一个非常大的地址周围以不可预测的方式增长(可能由于栈随机化),比如0x7fff282c783c。
将此与32位Intel Linux下的输出进行比较:
program: 0x804842f
heap: 0x804b008
heap2: 0x804b018
stack: 0xbf84ad38
stack2: 0xbf84ad14
Microsoft Windows 和 32 位 Microsoft C 编译器:
program: 01271020
heap: 002E3B00
heap2: 002E3B10
stack: 0024F978
stack2: 0024F964
在Windows Cygwin下使用gcc:
program: 0040130B
heap: 00A41728
heap2: 00A417A8
stack: 0028FF44
stack2: 0028FF14
在Intel 32位FreeBSD下使用gcc:
program: 0x8048524
heap: 0x804b030
heap2: 0x804b040
stack: 0xbfbffb3c
stack2: 0xbfbffb1c
在Intel 64位FreeBSD下使用gcc:
program: 0x400770
heap: 0x801006058
heap2: 0x801006060
stack: 0x7fffffffdaec
stack2: 0x7fffffffdabc
SPARC-64 FreeBSD下的gcc:
program: 0x100860
heap: 0x40c04098
heap2: 0x40c040a0
stack: 0x7fdffffe9ac
stack2: 0x7fdffffe8dc
运行 MacOS X 的 PowerPC:
program: 0x1ed4
heap: 0x100120
heap2: 0x100130
stack: 0xbffffba0
stack2: 0xbffffb38
在PowerPC上运行Linux:
program: 0x10000514
heap: 0x100c6008
heap2: 0x100c6018
stack: 0xbff45db0
stack2: 0xbff45d88
StrongARM运行NetBSD:
program: 0x1c5c
heap: 0x5030
heap2: 0x5040
stack: 0xefbfdcd0
stack2: 0xefbfdcb4
并且在运行 Linux 的 ARMv6 上:
program: 0x842c
heap: 0xb63008
heap2: 0xb63018
stack: 0xbe83eac4
stack2: 0xbe83eaac
正如你所看到的,可能性是无限的。
!address
扩展来为您确定这一点。我不知道*nix操作系统是否也适用。 - user1354557