19

Linuxman shmat逐字逐句:

返回值

[...] on error (void *) -1 返回,并设置 errno以指示错误的原因。

(POSIX 使用略有不同的措辞来表达相同的意思。)

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

4

3 回答 3

19

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

于 2012-11-09T11:12:14.030 回答
14

为简单起见,考虑一台具有 16 位地址空间的机器。这台机器可以寻址从 0 到 65535 的内存。在这种情况下(void*) -1,它与 0xffff 相同,即 65535。虽然从技术上讲,这个地址是有效的,但很少有系统可以在那里访问任何内容。

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


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

于 2012-11-09T11:10:41.673 回答
12

要直接回答这个问题,不,没有强制性规则、定义、标准或规范说(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之外是安全合理的,只是说不支持,不要这样做。

于 2012-11-09T14:14:47.087 回答