“(void*)”在“if (test == (void*) -1)”中的含义是什么?

9

该函数返回-1。

然而,在下面的代码中,(void*)的含义是什么:

没有它可以工作吗?

test = shmat(shm_id, NULL, 0);

if (test == (void *)-1) {
    /* handle shmat failure */
}

这看起来不像是可移植的 C 代码。你能加更多的标签吗? - Bathsheba
@Bathsheba posix... - Antti Haapala -- Слава Україні
兄弟,void表示空值。更多参考请查看:https://dev59.com/YF0a5IYBdhLWcg3w68cz - kannu
10
“void”和“void *”是两个不同的概念。我认为你需要至少获得50个声望值才能发表评论。 - ad absurdum
1
@kannu:语言不同,概念也不同。 - NewUser
2个回答

16

shmat 的原型如下:

void *shmat(int shmid, const void *shmaddr, int shmflg);

即它返回一个指向 void 的指针,而不是一个整数。

发生错误时,它将返回转换为指向 void 类型的指针的整数 -1。来自 Linux manpages shmat(2)

成功时,shmat() 返回已连接共享内存段的地址;出错时,返回 (void *)-1,并设置 errno 以指示错误原因。

这就是您必须正确进行比较以检查错误返回的方式。 C11 标准在 6.5.9p5-6 中对运算符 == 给出了以下说明:

5 否则,至少有一个操作数是指针。如果一个操作数是指针,另一个操作数是空指针常量,则将空指针常量转换为指针类型。

如果一个操作数是指向对象类型的指针,而另一个操作数是指向限定或未限定版本的 void 的指针,则前者被转换为后者的类型。

6 仅当两个指针都是空指针,都是指向同一对象(包括指向对象及其开头的子对象的指针或函数),都是指向同一数组对象的最后一个元素之后的指针,或者其中一个是指向一个数组对象之后的最后一个元素的指针,而另一个是指向立即跟随第一个数组对象的不同数组对象的开始的指针时,两个指针才相等。109)

也就是说,标准为确切的2种转换定义了行为:一个操作数是 void 指针,另一个操作数是其他类型的指针;或者一个操作数是指针,另一个操作数是空指针常量(即0或(void*)0等)。由于没有转换时 -1 不是空指针常量也不是指针,所以标准没有为这种情况指定任何行为,因此行为未定义"by the omission of any explicit definition"

test == -1 是错误的,test == (void *)-1 是正确的(ish)。

事实证明,这仍然是一个灰色地带。 -1 是一个 int,在我的计算机上是 32 位。将整数转换为指针由实现定义。 GCC 手册说

从指针到整数的转换会丢弃最高有效位,如果指针表示大于整数类型,则进行符号扩展[2];如果指针表示小于整数类型,则进行符号扩展[2];否则位保持不变。

脚注2说

GCC 的未来版本可以使用零扩展或使用目标定义的 ptr_extend 模式。 不要依赖符号扩展。

因此,这意味着 (void *)-1</


3
历史上,曾经可以映射到零页面(以便(void*)0成为一个有效的地址,可以在其中放置对象。这就是为什么mmap失败时不返回NULL的原因。我不知道这是否也适用于shmat,但这可能是此行为的原因。 - Florian Weimer
1
在64位系统上,难道不应该是test == (void *) -1L或者甚至是test == (void *) -1LL吗? - chqrlie
1
我的观点是,虽然GCC目前以那种方式执行,但这并不保证(未来)会进行符号扩展。 - Antti Haapala -- Слава Україні
5
mmapshmat的手册只提到了(void*)-1,而clang恰好将其实现为(void*)(inptr_t)-1,我猜所有符合Posix标准的编译器都必须这样做,以保持规范的一致性。这是一个有趣的边角案例。 - chqrlie
1
我想可以检查errno而不是试图从返回的指针中解码出错误状态。请注意,errno只在出现错误时设置,因此您必须在调用shmat之前显式清除它。 - Rodney
显示剩余4条评论

2

这是类型转换 (type casting)。

函数 shmat() 返回一个 void*,因此需要使用类型转换将 -1 (int) 转换为正确的类型 (void*)。

实际上,它可能会起作用,但你会收到一些来自编译器的警告。

永远不要忽略警告,它们可能隐藏着错误。


“……你会从编译器那里得到一些警告。” 你确定吗? - alk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接