0

有没有办法在 ANSI C89/ISO C90 中可移植地确定 void-pointer 值的上限和下限?(我目前没有标准的副本(我家里有一个)。当然,如果保证 void-pointer 值是无符号的,这个任务是微不足道的(通过 sizeof(void *));但是,我不能回想一下这是否得到保证。我可以想到一些非常低效的算法(递增直到溢出等),但我想知道是否有人有相对便宜(就时间复杂性而言)和可移植的方法计算这些界限。)

- 编辑 -

另外:是否有一种可移植的方法来确定指针值的有效性?

原因:这是在与一位同事的讨论中提出的,这让我很困惑。我不知道他在做什么,但我只是想知道,因为我有兴趣!:-)

4

6 回答 6

4

没有可移植的方法来确定给定指针是否有效。你必须知道你正在处理什么样的记忆系统。根据操作系统和处理器,可能有也可能没有查询虚拟内存管理器的页表以确定指针的有效范围的方法。

例如,在 Linux 上,您可以检查下面的特殊mmap文件/proc以获取进程的虚拟内存映射。下面是一个cat读取它自己的内存映射的例子:

$猫/proc/self/mmap
08048000-0804c000 r-xp 00000000 09:00 5128276 /bin/cat
0804c000-0804d000 rw-p 00003000 09:00 5128276 /bin/cat
0804d000-0806e000 rw-p 0804d000 00:00 0 [堆]
f7ca7000-f7e40000 r--p 00000000 09:00 3409654 /usr/lib/locale/locale-archive
f7e40000-f7e41000 rw-p f7e40000 00:00 0
f7e41000-f7f68000 r-xp 00000000 09:00 2654292 /lib/tls/i686/cmov/libc-2.3.6.so
f7f68000-f7f6d000 r--p 00127000 09:00 2654292 /lib/tls/i686/cmov/libc-2.3.6.so
f7f6d000-f7f6f000 rw-p 0012c000 09:00 2654292 /lib/tls/i686/cmov/libc-2.3.6.so
f7f6f000-f7f72000 rw-p f7f6f000 00:00 0
f7f83000-f7f85000 rw-p f7f83000 00:00 0
f7f85000-f7f9a000 r-xp 00000000 09:00 2637871 /lib/ld-2.3.6.so
f7f9a000-f7f9c000 rw-p 00014000 09:00 2637871 /lib/ld-2.3.6.so
ff821000-ff836000 rw-p 7ffffffea000 00:00 0 [堆栈]
ffffe000-fffff000 r-xp ffffe000 00:00 0 [vdso]

您可以看到有效指针的范围,以及指示内存是否为 (r) 可读、 (w) 可写、 e(x) 可执行或 (p) 可重新发送(即未分页到磁盘)的位。

于 2009-01-22T19:05:04.157 回答
0

规范保证指针是无符号的。但是你到底为什么要找到界限呢?“0x00000001 和 0xffffffff 之间的所有内容”并不是一个真正有用的测试,因为有效指针的数量只是其中的一小部分。

于 2009-01-22T18:43:07.727 回答
0

我知道在 Win32 上,64 位指针是符号扩展的。如果您不签署扩展指针,从 64 位机器检查 32 位小型转储会很有趣。

请参阅此处了解 64 位指针 ( POINTER_64) 如何在 Win32 上工作。

于 2009-01-22T19:00:09.597 回答
0

void * 总是大到足以容纳指向可寻址内存的指针。大联盟棒球协会严禁任何其他用途。

示例:dec-10 是具有 36 位字的 36 位架构。然而地址是 18 位,你可以在任何寄存器/字中保存 2 个指针。

是的 - 这是一个极端的例子。如果你必须用指针做数学,sizeof 是有效的;但是在连续数组以外的任何东西上进行指针数学运算都比狡猾。

最后 - 永远不要使用 'void *' 来存储指向对象的指针或指向 C++ 中成员的指针。许多编译器实现实际上使用多个“物理”指针来实现具体(或部分具体)类的多重继承。实际上,这几乎从来没有出现过,因为很少有人以这种方式使用多重继承,而且当他们这样做时,很少会分片和取消分片指针。当它出现时,真的很难弄清楚发生了什么。

于 2009-01-22T19:15:22.483 回答
0

void *您必须从内存中的实际位模式中辨别出可以将 a 转换为的整数值 - 将 avoid *转换为整数类型可能涉及转换!

假设sizeof(void *) == sizeof(long),对于 avoid * p以下很可能是错误的:

((long)p) == *((long *)&p)

此外,标准没有指定是否存在足够大的整数类型来保存所有有效指针的值!

因此,没有可移植的方式来做你想做的事......

于 2009-01-22T19:28:33.033 回答
0

除了对应于 NULL 的区域之外,对内存地址根本没有(可移植的)限制。一个充分强化的操作系统可以利用各种 CPU/OS 机制在每次调用 malloc() 时为每个进程提供随机且分布良好的地址,并且位置独立的可执行文件加上 ASLR 也可以允许代码从任何地址运行。

于 2009-01-23T03:32:42.277 回答