C “是什么意思?”;(无效*)”;in:if(test==(void*)-1)

C “是什么意思?”;(无效*)”;in:if(test==(void*)-1),c,posix,ipc,C,Posix,Ipc,函数返回-1 但是,以下代码中的(void*)是什么意思: 没有它能工作吗 test = shmat(shm_id, NULL, 0); if (test == (void *)-1) { /* handle shmat failure */ } shmat具有以下原型: void *shmat(int shmid, const void *shmaddr, int shmflg); i、 e.它返回指向void的指针,而不是整数 出错时,它会将整数-1转换返回到指向void的指针

函数返回-1

但是,以下代码中的
(void*)
是什么意思:

没有它能工作吗

test = shmat(shm_id, NULL, 0);

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

shmat
具有以下原型:

void *shmat(int shmid, const void *shmaddr, int shmflg);
i、 e.它返回指向
void
的指针,而不是整数

出错时,它会将整数-1转换返回到指向void的指针。从Linux手册页:

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

这就是您必须正确进行比较以检查错误返回的方式。C11标准对中的操作员
==
作了如下说明:

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

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

6两个指针比较相等当且仅当两个指针都是空指针,都是指向同一对象(包括指向对象的指针及其开头的子对象)或函数的指针,都是指向同一数组对象最后一个元素的指针,或者一个指针指向一个数组对象的末尾,另一个指针指向另一个数组对象的开头,该数组对象恰好紧跟地址空间中的第一个数组对象。109)

也就是说,标准定义了正好2次转换的行为:一个操作数是指向void的指针,另一个操作数是指向其他对象的指针;或者一个操作数是指针,另一个操作数是空指针常量(即0或(void*)0左右)。由于不带强制类型转换的
-1
既不是空指针常量,也不是指针,因此该标准没有为这种情况指定任何行为,因此该行为是未定义的

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

事实证明,这仍然是一个灰色地带
-1
是一个
int
,在我的计算机上是32位。整数到指针的转换由实现定义。委员会:

如果指针表示大于整数类型,则从指针到整数的强制转换将丢弃最高有效位;如果指针表示小于整数类型,则符号扩展,否则位将保持不变

脚注2说

GCC的未来版本可能会进行零扩展,或者使用目标定义的ptr_扩展模式。不要依赖符号扩展

因此,这意味着
(void*)-1
也可能变得不正确;更安全的方法是将其写成
(void*)(intptr\u t)-1


由于某种原因,
(void*)0
,即空指针,不用于信号错误条件(即使在C中使用该指针在标准方向上是错误的)。

是的

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

事实上,是的,它可以工作,但你会从编译器得到一些警告


永远不要忽视警告,因为它们可能隐藏bug。

在我看来不像便携式C。你能添加更多的标签吗?@Bathsheba posix…bro void表示空值。更多参考签出:-@kannu--
void
void*
是两件不同的事情。我以为你至少有50个代表才能发表评论…@kannu:语言不同,概念也不同。过去,可以映射零页(因此
(void*))0
变成可以放置对象的有效地址。这就是为什么
mmap
在失败时不返回
NULL
。我不知道这是否也适用于
shmat
,但这可能是此行为的原因。它是否应该是
test==(void*)-1L
甚至
test==(void*)-1LL
在64位系统上?我的观点是,虽然GCC目前是这样做的,但它不保证符号扩展(将来)。mmap和shmat的手册页只提到
(void*)-1
clang
碰巧实现了
(void*)-1
作为
(void*)(inptr\t)-1
我想所有符合Posix的编译器都必须这样做才能保持规范的一致性。有趣的是,我想人们可以检查
errno
,而不是试图从返回的指针中解码错误状态。请注意,
errno
仅在错误时设置,因此必须显式清除它在调用
shmat
“…编译器会给您一些警告”之前,您确定吗?