这是什么意思:指向 void 的指针永远不会等于另一个指针?

What does this mean: a pointer to void will never be equal to another pointer?

我的一个朋友从“理解和使用 C 指针 - Richard Reese,O'Reilly 出版物”中指出了第二个要点,我无法解释 第一个 句起。我错过了什么?

Pointer to void

A pointer to void is a general-purpose pointer used to hold references to any data type. An example of a pointer to void is shown below:

void *pv;

It has two interesting properties:

  • A pointer to void will have the same representation and memory alignment as a pointer to char.
  • A pointer to void will never be equal to another pointer. However, two void pointers assigned a NULL value will be equal.

这是我的代码,不是书中的代码,所有指针都具有相同的值且相等。

#include <stdio.h>

int main()
{
  int a = 10; 
  int *p = &a; 
  void *p1 = (void*)&a;
  void *p2 = (void*)&a;

  printf("%p %p\n",p1,p2);
  printf("%p\n",p);
  
  if(p == p1) 
    printf("Equal\n");
  if(p1 == p2) 
    printf("Equal\n");  
}

输出:

 0x7ffe1fbecfec 0x7ffe1fbecfec
 0x7ffe1fbecfec
 Equal
 Equal

以下部分来自 this Draft C11 Standard completely refutes the claim made (even with the clarification mentioned in the 'errata', in the )。

6.3.2.3 Pointers

1     A pointer to void may be converted to or from a pointer to any object type. A pointer to any object type may be converted to a pointer to void and back again; the result shall compare equal to the original pointer.

或者,此部分来自同一标准草案:

7.20.1.4 Integer types capable of holding object pointers

1    The following type designates a signed integer type with the property that any valid pointer to void can be converted to this type, then converted back to pointer to void, and the result will compare equal to the original pointer:

      intptr_t

C 2018 6.5.9 6 说:

Two pointers compare equal if and only if both are null pointers, both are pointers to the same object (including a pointer to an object and a subobject at its beginning) or function, both are pointers to one past the last element of the same array object, or one is a pointer to one past the end of one array object and the other is a pointer to the start of a different array object that happens to immediately follow the first array object in the address space.

所以,假设我们有:

int a;
void *p0 = &a;
void *p1 = &a;

然后,如果p0p1“指向同一个对象”,p0 == p1必须评估为真。但是,有人可能会将标准解释为 void * 不指向任何东西,而它是 void *;它只包含将其转换回其原始类型所需的信息。但是我们可以检验这个解释。

考虑两个指针比较相等的规范,如果它们在开头指向一个对象和一个子对象。这意味着给定 int a[1];&a == &a[0] 应该评估为真。但是,我们不能正确使用 &a == &a[0],因为 == 对指针的约束要求操作数指向兼容类型,或者其中一个或两个都是 void *(带有限定符 const 允许)。但是 aa[0] 既没有兼容的类型,也没有 void.

出现完全定义情况(我们正在比较指向此对象及其子对象的指针)的唯一方法是至少将其中一个指针转换为 void * 或指针到字符类型(因为这些在转换中得到特殊处理)。我们可以将标准解释为仅表示后者,但我认为更合理的解释是包含 void *。目的是将 (void *) &a == (void *) &a[0] 解释为指向对象 a 的指针与指向对象 a[0] 的指针的比较,即使这些指针的形式为 void *.因此,这两个 void * 应该比较相等。

TL/DR: 书错了

What am I missing?

据我所知,没有。即使是评论中出现的勘误版本...

A pointer to void will never be equal to another pointer to void.

... C 语言规范根本不支持。如果作者依赖语言规范,相关文本将是第 6.5.9/6 段:

Two pointers compare equal if and only if both are null pointers, both are pointers to the same object (including a pointer to an object and a subobject at its beginning) or function, both are pointers to one past the last element of the same array object, or one is a pointer to one past the end of one array object and the other is a pointer to the start of a different array object that happens to immediately follow the first array object in the address space.

void 是一种对象类型,尽管是“不完整”的类型。指向有效且非空的 void 的指针是指向对象的指针,它们在规范表达的条件下相互比较相等。获得此类指针的通常方法是将不同(指针)类型的对象指针转换为 void *。这种转换的结果仍然指向与原始指针相同的对象。

我最好的猜测是这本书误解了规范,指出指向 void 的指针不应被解释为指向对象的指针。尽管有一些特殊情况仅适用于指向 void 的指针,但这并不意味着适用于对象指针的一般规定也不适用于 void 指针。

指针只是内存中的一个地址。如果两个指针为 NULL 或指向同一地址,则它们相等。您可以继续讨论结构、联合等语言如何实现这一点。但最终,它只是带有内存位置的代数。

  • A pointer to void will never be equal to another pointer. However, two void pointers assigned a NULL value will be equal.

由于该声明中提到了 NULL,我认为这是一个错误输入。该声明应该类似于

  • 指向 void 的指针永远不会等于 NULL 指针。但是,分配了 NULL 值的两个空指针将相等。

这意味着任何指向 void 的有效指针永远不会等于 NULL 指针。