对 C 中的指针和泛型(void)指针感到困惑

Confused about the pointers and generic(void) pointers in C

我错过了几个 类,并且不太理解流畅的讲座幻灯片中关于 void 指针的示例。

  1. 在"no,no,no"行中,既然P已经被赋予了一个真正的指针类型q,为什么我们不能推导P?

  2. 在“??”行中,将指针转换为整数是否合法? (我认为它可以编译,因为 C 不检查转换,但不知道它会得到什么样的结果

在这个例子中 Conversion of integer pointer to integer
他投了 *p = 10; a = (整数)p; 有人回答说 a 将是一个非常大的值。 但就我而言,是 (int) *p... 是否与我上面给出的示例相同?

  1. 在最后一行,我对表达感到困惑。 * ((int *)p) 实际上 = p 吗? 谢谢!

空指针特指没有关联数据类型的指针。您必须将它们重新转换为特定类型(即:int*)才能访问其内容。

澄清您的具体观点:

1) 虽然 p 可能有一个指针地址,但它没有与之关联的特定数据类型(访问内容需要数据类型)

2) 此操作的结果可能对内容具有确定性。我不推荐这是一个好习惯。

3) 这是告诉编译器将 void 指针视为整数指针。因此,它 "knows" 与之关联的数据类型,并将其作为 int 进行访问。

"void*" 表示 "this value is a pointer to something, but I'm not telling you what it points to"。从这句话开始,一切都说得通了。

所以应该清楚您不能取消对 void* 的引用,因为没有人告诉您它指向什么!如果您不知道它是指向一个 int、一个 char 还是某个结构,您认为如果您取消引用它会发生什么?

在 C 中,您可以将 void* 分配给任何指针,例如分配给 int*。编译器 不知道 void* 指向什么,但是当你写 r = p;编译器说 "I hope you know what you are doing, I trust you. " (同样情况下的 C++ 编译器不信任你)。如果 void* p 确实指向一个 int,那么一切都很好。否则,事情或多或少会很糟糕。

那个??一个是错误的。您不能取消引用 *p。不管你之后做什么, *p 是不允许的。并且没有指针被转换为整数。尝试取消引用指针,这是不允许的。取消引用的结果没有任何用处,因为您不知道 p 指向什么,因此您没有任何用处可以转换为 int。

现在 * (int *) p 中发生了什么:p 是一个 void * - 指向某物的指针,但您不知道它指向什么。 (int * )p 是一个转换:p 被转换为一个 int*。这意味着编译器将相信 (int*)p 指向一个 int - 这可能是也可能不是真的。 * (int * ) p 取消对 int* 的引用:总的来说,您说服了编译器 p 指向一个 int,并读取 p 希望指向的 int。如果 p 确实指向一个 int,那很好。如果 p 没有指向一个 int,你就有麻烦了。

In the line "no,no,no", why we cannot deference P since P has been assigned a real pointer type q?

int a =2, *q = a, *r; //line 1
void *p;  //line 2
p = q; // line 3
r = p; // line 4

在上面的第 3 行中,您将指针 q 分配给 p。但它不会改变 p 的类型——它仍然是一个空指针。所以你不能取消引用它。所以下面是无效的:

printf("%d\n", *p); // p is a void pointer - dereferencing here is illegal

或者,您可以这样做:

printf("%d\n", *((int*) p)); // p is a void pointer

以上有效。因为,我们在取消引用之前将 p 转换为 int *。考虑一个例子,

void func(void *p)
{
   // what's `p` point to here?
}

int main(void)
{
   int i = 5;
   long x = 10;
   void *p;

   p = &i; // line 1
   p = &x; //line 2

func(p);
}

您可以注释掉第 1 行或第 2 行,但无论如何 func() 中是否存在以了解 p 是指向 long 数据还是 int 数据?这与您的情况没有什么不同。

但是在访问其指向的数据之前,始终需要从 void *type *(数据指针)的转换。请注意,它不能是 any 数据指针。例如,

int i = 42;
float f = 4.0;

void *p = &f;

printf("%d\n", *((int*))p); // wrong!

这是非法的。 p 指向一个 float *。取消引用就好像它指向 int 数据是错误的。


In the line " ?? ", is it legal to cast a pointer to a integer?

printf("%d\n", (int) *p);

因为 p 是一个 void*,所以一开始就不允许取消引用。取消引用后的转换不会改变任何内容,并且取消引用是非法的。

如果您要像这样转换指针本身:

printf("%d\n", (int)p);

这在 C 中具有 实现定义的 行为。C 还提供 intptr_t/uintptr_t 类型用于整数到指针的转换。

如果指针 p 的类型为 void *,则表达式 *p 的类型为 void,而 void 类型没有值1;这就是为什么在取消引用之前必须将指针转换为 "real" 指针类型的原因。

指针和整数可以相互转换,但不保证这些值是有意义的。但是,这不是标记为 ?? 的行所做的;它试图取消引用 p 并转换结果,但由于 p 是指向 void 的指针,这是不允许的。

表达式 *((int *) p)p 从指向 void 的指针强制转换为指向 int 的指针并取消引用结果。由于 p 指向 a,因此计算结果为 a (2).


1。 void类型是不完整类型,无法完成。