ANSI C89 / ISO C90中void指针的界限

时间:2009-01-22 18:40:12

标签: c void-pointers c89

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

- 编辑 -

另外:是否有可行的方法来确定指针值的有效性?

为什么:这是与同事讨论的结果,让我感到难过。我不知道他在做什么,但我只是想知道因为我感兴趣! : - )

6 个答案:

答案 0 :(得分:4)

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

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

$ 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                                  [heap]
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                              [stack]
ffffe000-fffff000 r-xp ffffe000 00:00 0                                  [vdso]

你可以看到有效指针的范围,以及指示内存是否可以(r)可用,(w)ritable,e(x)ecutable,或(p)重新发送(即没有分页到磁盘)的位

答案 1 :(得分:0)

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

答案 2 :(得分:0)

我知道在Win32上,64位指针是符号扩展的。如果不对扩展指针进行签名,那么从64位计算机检查32位小型转储是很有趣的。

请参阅here了解64位指针(POINTER_64)如何在Win32上运行。

答案 3 :(得分:0)

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

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

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

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

答案 4 :(得分:0)

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

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

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

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

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

答案 5 :(得分:0)

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