返回值
返回[...] on error(void *) - 1,并设置 errno 以指示错误原因。
(POSIX使用slightly different wording告诉他们。)
是否有(void *) -1
可能不是有效地址的强制性规则或定义(标准?)?
答案 0 :(得分:19)
0xffffffff
在技术上是32位环境中的有效地址,但在大多数操作系统(当然是Linux / Windows)上都将位于地址空间的保留内核部分。这意味着在用户模式进程中,将其用作错误代码是安全的,因为没有用户模式分配函数会将其作为可用地址返回。
答案 1 :(得分:14)
为简单起见,请考虑具有16位地址空间的计算机。这台机器可以处理从0到65535的内存。在这种情况下,(void*) -1
将与0xffff相同,即65535.虽然从技术上讲这个地址是有效的,但是很少有系统可以在那里有任何它们允许的内容。访问。
另一件需要考虑的事情是,几乎所有POSIX系统调用都会在出错时返回-1
。
如Benj所述,实际上可以映射地址NULL
。例如,当您想要查看是否存在具有指定shmid
的映射时,可以使用此选项,在这种情况下,shmaddr
参数设置为NULL
,函数返回{{1表示共享内存存在。
答案 2 :(得分:10)
要直接回答这个问题,请注意,没有强制性规则,定义,标准或规范说(void *) -1
可能不是有效地址。
(当然,没有关于内存地址的规则,定义,标准或规范是强制性的。例如,我看到人们每天走在街上而不符合C标准,但我从未见过有人因此而被捕但是,即使我们省略了强制性部分,使用(void *) -1
作为地址通常也不会被普通规范禁止。)
但是,(void *) -1
没有必要不是有效的地址才能使shmat工作。只需要对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中统治这个案例是安全和合理的,只是说不支持,不要这样做。