((void *)-1)是一个有效的地址吗?

来自man shmat逐字:

返回值

返回错误(void *)-1,并设置errno以指示错误原因。

(POSIX使用略有不同的措辞来讲述相同的内容。)

是否有任何强制性规则或定义(标准?) (void *) -1可能不是有效地址?

要直接回答这个问题,不,没有强制性规则,定义,标准或规范说(void *) -1可能不是有效地址。

(当然,没有关于内存地址的规则,定义,标准或规范是强制性的。例如,我看到人们每天走在街上而不符合C标准,但我从未见过有人因此而被捕。但是,即使我们省略了强制性部分,使用(void *) -1作为地址通常也不会被通用规范禁止。)

但是,为了使shmat工作, (void *) -1不必是有效地址。 只需要成功调用shmat永远不会返回(void *) -1并且编译器支持(void *) -1以便测试来自shmat的返回值。 如果满足这两个条件,那么程序总能将成功的shmat调用与不成功的shmat调用区分开来。

关于第二个条件,C标准不保证可以使用(void *) -1 ,因此POSIX在指定这是从shmat返回的错误时,隐式地要求C(或其他语言)实现来支持它。 所以这是对POSIX所需语言的扩展,对于编译器来说通常是一件简单的事情。

关于第一个条件,考虑什么时候我们可能希望shmat返回(void *) -1以成功调用。 shmat可以使用用户请求的地址调用,也可以不使用,在这种情况下,实现选择一个地址。 在任何正常的计算机体系结构中,使用多个不同值的地址有多种原因。 对于shmat,最明显的是内存映射。 在具有虚拟内存的体系结构中,内存以页为单位进行映射,而shmat在映射内存时将映射到页面的开头。 任何偶数页面大小都没有(void *) -1倍数,因为后者是奇数,所以shmat从不选择将段映射到(void *) -1 。 即使shmat没有使用页面大小,它通常也会使用其他一些对齐方式,例如4,8或16个字节,因为提供对齐的内存意味着存储在该内存开头的结构将对齐,从而导致更快的内存访问许多处理器。

这留下了用户请求(void *) -1作为地址的情况。 这可能是不寻常的,只有当内存段是单个字节或内存模型允许环绕时才会起作用(或者编译器提供了一个非常奇怪的内存模型,其中(void *) -1不是最后一个字节)地址空间)。 我无法确定是否有任何POSIX系统支持这一点。 然而,很明显,这基本上是没用的,没有任何理由除了好奇之外还有其他的理由。 因此,从shmat中统治这个案例是安全和合理的,只是说不支持,不要这样做。

0xffffffff在技​​术上是32位环境中的有效地址,但在大多数操作系统(当然是Linux / Windows)上将位于地址空间的保留内核部分。 这意味着在用户模式进程中将其用作错误代码是安全的,因为没有用户模式分配函数会将其作为可用地址返回。

为简单起见,请考虑具有16位地址空间的计算机。 这台机器可以处理0到65535之间的内存。在这种情况下(void*) -1将与0xffff相同,即65535.虽然从技术上讲这个地址是有效的,但是很少有系统可以提供任何允许的内容。被访问。

另一件需要考虑的事情是几乎所有POSIX系统调用都会在出错时返回-1


正如Benj所指出的,实际上可以将地址映射为NULL 。 例如,当您想要查看是否存在具有指定shmid的映射时,可以使用此shmid ,在这种情况下, shmaddr参数设置为NULL ,函数返回NULL以表示共享内存存在。