我需要函数指针的帮助。
我有两个函数指针类型:
typedef void (*draw_func1_t)(void* data, void* painter, double x, double y);
typedef void (*draw_func2_t)(void* data, MyPainter* painter, double x, double y);
除了第二个参数外,这两种类型几乎相同。现在我需要编写一个将draw_func1_t转换为draw_func2_t的函数:
draw_func2_t convert_func_p(draw_func1_t func) { ... }
我怎么写呢?我可以强迫演员像
return (draw_func2_t)func;
因为两个函数原型是二进制兼容的吗?
答案 0 :(得分:5)
如果将函数指针强制转换为其他类型,则其调用的行为未定义。见C标准的附录J.2:
在以下情况下,行为未定义:指针 用于调用类型与其不兼容的函数 指向型(6.3.2.3)。
兼容性在6.7.5.1第2段中处理:
要使两个指针类型兼容,两者应完全相同 限定,两者都是兼容类型的指针。
MyPainter*
与void*
不兼容。因此,您的函数指针强制转换不能用于调用函数。
答案 1 :(得分:1)
自使用以来:
HttpRequest.CreateResponse()
导致未定义的行为,您可能想要更改策略。
说你有:
draw_func1_t convert_func_p(draw_func2_t func)
{
return (draw_func1_t)func;
}
并且您希望能够通过函数指针间接使用该函数。
一种选择是使用包装函数。
void func2(void* data, MyPainter* painter, double x, double y)
{
printf("In func2, working with MyPainter\n");
}
注册void func2_wrapper(void* data, void* painter, double x, double y)
{
// In this function, if you are sure that painter points to
// a valid MyPainter object, you can do this:
MyPainter* realPainter = (MyPainter*)painter;
// Then call the core function.
func2(data, realPainter, x, y);
}
作为回调。
您还可以通过删除func2_wrapper
的显式转换来简化func2_wrapper
。
MyPainter*
答案 2 :(得分:0)
理论上,如果你将它转换为不同的签名并调用它,那么它是未定义的行为,正如Bathsheba的答案所引用的那样,因为调用不同类型函数的调用约定可能不同。
然而,实际上,它几乎适用于任何真实世界的系统,因为几乎所有的调用约定都相同地处理不同类型的(非函数)指针。由于这是唯一的区别(其他一切,包括参数的数量和返回类型是相同的),调用约定几乎肯定是相同的。您可以检查特定系统的函数调用ABI以确保。
答案 3 :(得分:0)
以下编译时没有警告(VC2008),并显示两种功能类型兼容。出乎意料的是,在void *
被要求的情况下接受MyPainter *
。
typedef struct {
int x;
int y;
} MyPainter;
typedef void (*draw_func1_t)(void* data, void* painter, double x, double y);
typedef void (*draw_func2_t)(void* data, MyPainter* painter, double x, double y);
void f1(void* data, void* painter, double x, double y);
void f2(void* data, MyPainter* painter, double x, double y);
void f1(void* data, void* painter, double x, double y)
{
f2(data,painter,x,y); // no compiler warning is unexpected
}
void f2(void* data, MyPainter* painter, double x, double y)
{
f1(data,painter,x,y); // no compiler warning is expected
}
void pTest(void)
{
MyPainter p = {0,0};
draw_func1_t pf1;
draw_func2_t pf2;
pf1= f1;
pf2= f1;
pf1= f2;
pf2= f2;
pf1(0,&p,0.0,0.0);
pf2(0,&p,0.0,0.0);
}