【问题标题】:Conversion between a void pointer and a pointer to function pointervoid指针和指向函数指针的指针之间的转换
【发布时间】:2015-06-09 00:29:56
【问题描述】:

我知道void * 并且函数指针无法安全地转换。

我的问题是下面的代码。

#include <stdio.h>
#include <stdlib.h>

void f(void *);

void g(void) {
    printf("hello world\n");
}

int main(void) {
    void (*p)(void) = g;
    void (**pp)(void) = malloc(sizeof(void (*)(void)));
    pp = &p;
    f(pp);
    free(pp); //segfault
    return EXIT_SUCCESS;
}

void f(void *p) {
    (*(void (**)(void))p)();
}

它在 gcc 中使用 -Wall -Wextra -pedantic -std=c99 编译得很好,但在程序调用 free 时在运行时失败。在这种情况下有什么问题?指向函数指针的指针不是数据指针吗?

三思而后行:

正确的代码是这样的,

int main(void) {
    void (*p)(void) = g;
    f(&p);
    return EXIT_SUCCESS;
}

我不知道为什么我会感到困惑:/

【问题讨论】:

  • pp 已经被&amp;p 重写。 free(pp) 是 UB。
  • 我认为您需要阅读malloc() 并深入了解它的作用和用途。

标签: c pointers function-pointers


【解决方案1】:

您的代码中有一个错误:

您首先为函数指针分配空间并将地址存储在pp中。

void (**pp)(void) = malloc(sizeof(void (*)(void)));

然后你立即用本地函数函数p的地址覆盖它:

pp = &p;

你调用f(),它又调用传递地址处的函数指针。

f(pp);

最后你尝试free 局部变量的地址,这是未定义的行为,你的环境崩溃了。

free(pp); //segfault

您可能打算将p 的值存储在分配的对象中,而不是pp = &amp;p;

*pp = p;

您关于转换void * 和函数指针的评论是正确的:void * 指针不能安全地转换为void(*)(),反之亦然。对象指针和函数指针可能有不同的不兼容表示。

在您的情况下,您将 void * 返回值从 malloc() 隐式转换为指向函数指针 void (**)() 的指针。这种转换是正确的,因为malloc 被定义为返回一个适合存储任何对象类型的指针(只要分配了足够的空间)。

相反,当将指针pp 传递给f 时,您将其隐式转换为void *,而后者又将其转换回void (**)()。定义这样的转换是因为任何对象指针都可以安全地转换为void * 并返回其原始类型。为了完整起见,所有函数指针都可以安全地从一种类型转换为另一种类型,只要它们在调用之前转换为所引用函数的实际类型即可。

【讨论】:

  • 最后一句话。 OP 这样做了两次:malloc 返回一个 void* 指针,该指针转换为函数指针,并将函数指针传递给 f()。
  • @2501: 否,malloc 返回一个void*,该void* 被转换为指向函数指针的指针,f 被传递一个指向可以转换为@987654347 的函数指针的指针@ 并返回。
  • 不,malloc 返回一个 void*,它被转换为指向函数指针的指针 矛盾:你关于转换 void* 和函数指针的评论是正确的,但是你在你的代码中没有做这样的事情。 ??????将函数指针转换为对象指针在 C 中是未定义的。甚至 OP 都知道:我知道 void* 并且函数指针不能以任何一种方式安全地转换。
  • @2501:OP 知道这一点,我承认这一点。 OP 不会将void* 指针转换为函数指针,而只是转换为指向函数指针的指针。类型 void (**)() 是一个 data 指针。我更新了我的答案以使其更加明确。
猜你喜欢
  • 2014-09-05
  • 2021-07-22
  • 1970-01-01
  • 1970-01-01
  • 2011-07-31
  • 1970-01-01
  • 1970-01-01
  • 2012-11-21
  • 2011-04-26
相关资源
最近更新 更多