我知道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
我不知道为什么我感到困惑:/
答案 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 *
,然后将其传递给f
,void (**)()
又将其转换回void *
。定义了这样的转换,因为任何对象指针都可以安全地转换为{{1}}并返回其原始类型。为了完整性,所有函数指针都可以安全地从一种类型转换为另一种类型,只要它们在调用之前转换为引用的函数的实际类型即可。