【问题标题】:Confused about the pointers and generic(void) pointers in C对 C 中的指针和泛型(void)指针感到困惑
【发布时间】:2016-03-11 10:47:28
【问题描述】:

我错过了几节课,并不真正理解流畅的讲座幻灯片中关于 void 指针的示例。

  1. 在“no,no,no”行中,为什么我们不能尊重 P,因为 P 已经被分配了一个真正的指针类型 q?

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

在这个例子中 Conversion of integer pointer to integer
他投了 *p = 10; a = (int)p; 有人回答说 a 将是一个非常大的值。 但在我的情况下,is (int) *p... 和我上面给出的例子一样吗?

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

【问题讨论】:

  • “分配”和“分配给”是相反的。它说要使用p,您必须将其值赋给另一个变量(例如int *q = p;),然后使用该另一个变量。 (或演员)。

标签: c pointers void-pointers generic-programming


【解决方案1】:

“void*”的意思是“这个值是一个指向某物的指针,但我没有告诉你它指向什么”。从这句话开始,一切都说得通。

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

在 C 中,您可以将 void* 分配给任何指针,例如 int*。编译器不知道 void* 指向什么,但是当你写 r = p;编译器说“我希望你知道你在做什么,我相信你。”(同样情况下的 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,那么你就有麻烦了。

【讨论】:

  • "你不能取消引用 *p" -> "你不能取消引用 p"
【解决方案2】:

Void 指针特别是没有与之关联的数据类型的指针。您必须将它们重铸为特定类型(即:int*)才能访问它们的内容。

澄清你的具体观点:

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

2) 这个动作的结果可能对内容是确定的。我不建议将此作为一种好习惯。

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

【讨论】:

  • 是的,但是上面的讲座幻灯片还说另一种方式是“分配给读取指针类型”。在“p=q”行中,void 指针 p 被分配给一个真正的指针类型 q(q 是 int*)。所以我认为 p 可以在 "no, no, no" 行中取消引用
  • @overloading p 被分配了q 的值;它与类型无关。在double d = 5.3; int i; i = d; 之后,我们是否说i 被分配了double 类型?
【解决方案3】:

在 "no,no,no" 行中,为什么我们不能尊重 P,因为 P 已经 分配了一个真正的指针类型 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);
}

您可以注释掉 line1 或 line2,但无论如何在 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 数据一样取消引用是错误的。


在“??”行中,将指针强制转换为整数是否合法?

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

由于pvoid*,因此首先不允许取消引用。取消引用后的强制转换不会改变任何内容,并且取消引用是非法的。

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

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

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

【讨论】:

  • 如果没有合适的整数对应于该指针,(int)p 可能会导致未定义的行为。有人称这种情况为“实现未定义的行为”,即它是实现定义的,但实现可能定义它是未定义的
  • 是的。 C 标准允许这样做: 整数可以转换为任何指针类型。除非前面指定,结果是实现定义的,可能未正确对齐,可能不指向引用类型的实体,并且可能是陷阱表示。所以它也可能是未定义的。
  • @M.M 根据这个答案,这是不可能的:stackoverflow.com/questions/30190011/… 实现 defined 行为不能是 undefined
  • 您引用了“整数可以转换为任何指针类型”,但是我们正在谈论将指针转换为整数。在你引用的那一段之后阅读下一段
  • 哈!以下是相关部分: 任何指针类型都可以转换为整数类型。除非前面指定,结果是实现定义的。如果结果不能以整数类型表示,则行为未定义。结果不必在任何整数类型的值范围内。
【解决方案4】:

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

指针和整数可以相互转换,但不保证值是有意义的。然而,这不是标有?? 的行正在做的事情。它试图取消引用p 并转换结果,但由于p 是指向void 的指针,因此这是不允许的。

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


1。 void 类型是一个无法完成的不完整类型。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-25
    • 1970-01-01
    • 1970-01-01
    • 2014-09-26
    • 1970-01-01
    相关资源
    最近更新 更多