空指针和指向函数指针的指针之间的转换
Conversion between a void pointer and a pointer to function pointer
我知道 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)();
}
它在 -Wall -Wextra -pedantic -std=c99
的 gcc 中编译良好,但在程序调用 free
时在运行时失败。在这种情况下有什么问题?指向函数指针的指针不是数据指针吗?
事后思考:
正确的代码是这样的,
int main(void) {
void (*p)(void) = g;
f(&p);
return EXIT_SUCCESS;
}
我不知道为什么我感到困惑:/
您的代码中存在错误:
你首先为一个函数指针分配space并将地址存储在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 *
return 值从 malloc()
隐式转换为指向函数指针 void (**)()
的指针。这种转换是正确的,因为 malloc
被定义为 return 适合存储任何对象类型的指针(假设分配了足够的 space)。
反过来,当将指针 pp
传递给 f
时,您将其隐式转换为 void *
,后者又将其转换回 void (**)()
。定义这样的转换是因为任何对象指针都可以安全地转换为 void *
并返回其原始类型。为了完整起见,所有函数指针都可以安全地从一种类型转换为另一种类型,只要在调用它之前将它们转换为引用函数的实际类型即可。
我知道 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)();
}
它在 -Wall -Wextra -pedantic -std=c99
的 gcc 中编译良好,但在程序调用 free
时在运行时失败。在这种情况下有什么问题?指向函数指针的指针不是数据指针吗?
事后思考:
正确的代码是这样的,
int main(void) {
void (*p)(void) = g;
f(&p);
return EXIT_SUCCESS;
}
我不知道为什么我感到困惑:/
您的代码中存在错误:
你首先为一个函数指针分配space并将地址存储在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 *
return 值从 malloc()
隐式转换为指向函数指针 void (**)()
的指针。这种转换是正确的,因为 malloc
被定义为 return 适合存储任何对象类型的指针(假设分配了足够的 space)。
反过来,当将指针 pp
传递给 f
时,您将其隐式转换为 void *
,后者又将其转换回 void (**)()
。定义这样的转换是因为任何对象指针都可以安全地转换为 void *
并返回其原始类型。为了完整起见,所有函数指针都可以安全地从一种类型转换为另一种类型,只要在调用它之前将它们转换为引用函数的实际类型即可。