shmat 有以下原型:
void *shmat(int shmid, const void *shmaddr, int shmflg);
即它返回一个指向void 的指针,而不是一个整数。
如果出错,它将返回 整数 -1 转换为指向 void 的指针。来自 Linux 手册页shmat(2):
成功时,shmat() 返回附加的共享内存段的地址;出错时,返回(void *) -1,并设置errno 指示错误原因。
这就是您必须正确进行比较以检查错误返回的方式。 C11 标准对6.5.9p5-6 中的运算符== 有如下说明:
5 否则,至少有一个操作数是指针。如果一个操作数是指针而另一个是空指针常量,则空指针常量将转换为指针的类型。
如果一个操作数是一个指针指向一个对象类型而另一个是一个指针指向一个合格或不合格的void版本,前者被转换为后者。
6 两个指针比较相等当且仅当两者都是空指针,两者都是指向同一个对象(包括指向对象的指针和在其开头的子对象)或函数的指针,两者都是指向最后一个元素的指针同一个数组对象,或者一个是指向一个数组对象末尾的指针,另一个是指向另一个数组对象的开头的指针,该数组对象恰好紧跟在地址空间中的第一个数组对象之后。109)
也就是说,标准定义了两种转换的行为:一个操作数是指向 void 的指针,另一个操作数是指向其他对象的指针;或者一个操作数是指针,而另一个操作数是空指针常量(即 0 或 (void*)0 等)。由于没有强制转换的-1 既不是空指针常量也不是指针,因此标准没有为这种情况指定任何行为,因此行为未定义"by the omission of any explicit definition"。
test == -1 是错误的,test == (void *) -1 是正确的(ish)。
事实证明,这仍然是一个灰色区域。 -1 是 int,在 my 计算机上,它是 32 位的。整数到指针的转换由实现定义。 GCC manuals say:
如果指针表示大于整数类型,则从指针到整数的强制转换丢弃最高有效位,如果指针表示小于整数类型,则符号扩展[2],否则位没有变化。
脚注2说
GCC 的未来版本可能会进行零扩展,或使用目标定义的 ptr_extend 模式。不要依赖符号扩展。
因此这意味着(void *)-1 也可能变得不正确;更安全的方法是将其写为(void *)(intptr_t)-1。
由于某种原因,(void *)0,即空指针,不用于指示错误条件(即使在 C 中使用这样的指针在标准方面是错误的)。