void指针和指向函数指针的指针之间的转换

时间:2015-06-09 00:29:56

标签: c pointers function-pointers

我知道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很好地编译,但在程序调用{​​{1}}时在运行时失败。这种情况有什么问题?指向函数指针的指针不是数据指针吗?

有感:

正确的代码就是这个,

free

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

1 个答案:

答案 0 :(得分:2)

您的代码中存在错误:

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

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

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

pp = &p;

你调用f(),然后调用传递地址的函数指针。

f(pp);

最后,您尝试free本地变量的地址,这是未定义的行为,是您环境的崩溃。

free(pp); //segfault

而不是pp = &p;,您可能意味着将p的值存储在已分配的对象中:

*pp = p;

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

在您的情况下,您隐式地将void *返回值从malloc()转换为指向函数指针void (**)()的指针。此转换是正确的,因为malloc被定义为返回适合存储任何对象类型的指针(提供足够的空间)。

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

相关问题