转换函数指针

3

If I have a prototype that is declared as:

void foo(int (*fi)(void *, void *))

我会像这样调用函数:

foo(int (*)(void*, void*)(bool_expr ? func1 : func2));

func1和func2的定义如下:

int func1(char *s1, char *s2);
int func2(int *i1, int *i2);

函数调用是否将函数(func1 ^ func2)中的一个转换为foo所需的函数类型?我也可以将foo的原型看起来像:

void foo(int (*)(void *, void *))

这个符号 ^ 应该是什么意思? - Roman Byshko
“^”是我的异或运算符的简写,因为你将会转换其中一个函数而不是两个或没有。我希望这样能够澄清事情。 - Matthew Hoggan
我不确定那会不会编译通过。 - Oliver Charlesworth
1
你能举个例子说明这在哪些情况下会有用吗? - Oliver Charlesworth
3个回答

2
根据C规范,对函数指针进行强制转换会导致未指定的行为,但许多编译器(例如gcc)会执行您所期望的操作,因为函数指针只是内存中的地址。 为了安全起见,我建议重新声明func1和func2以使用void*,然后根据需要将这些指针转换为char*和int*。

将函数指针强制转换不会导致未定义行为。通过不兼容的指针类型调用函数会导致未定义行为。 - ninjalj
1
这并不完全符合C标准的规定。通过一个类型与函数实际类型不兼容的指针调用函数会导致未定义(而非仅仅是未指定)的行为。将函数指针强制转换为任何函数指针类型都是有效的,只要在任何调用中使用的类型是正确的。 - Keith Thompson

2
在GCC中,这个表达式:
bool_expr ? func1 : func2

会给出这个警告:

warning: pointer type mismatch in conditional expression

即使您不打开特殊警告,GCC也会解决此指针类型不匹配问题;因此,当您尝试将其强制转换回来(无论是显式地使用 (int (*)(void*, void*)) 还是隐式地通过传递给 foo),它都会生成此警告并将两个表达式都转换为 void * 类型。
warning: ISO C forbids conversion of object pointer to function pointer type

如果您启用了过度严格模式(pedantry),那么编译器会禁止这样做。(ISO C之所以禁止这样做是因为函数指针在内部实现时不一定要作为指向内存位置的指针,因此它可能与常规的“对象”指针大小等方面不同。)
话虽如此,以下内容:
foo((bool_expr ? (int (*)(void*, void*))func1 : (int (*)(void*, void*))func2));

只要foofunc1传递有效的char指针或向func2传递有效的int指针,就应该相对安全。

我猜想,在一个函数指针与void *真正不兼容的系统上,编译器不会在bool_expr ? func1 : func2中解决类型不匹配的问题,而是采用void *(虽然我没有查阅规范)。


1

正如所评论的那样,发布的代码无法编译。

顺便说一下,这段代码可以在VC2010中编译和执行,与您的预期相符:

int func1(char *s1, char *s2) { printf("func1\n"); return 0; }
int func2(int *i1, int *i2)   { printf("func2\n"); return 0; }

void foo(int (*)(void *, void *));

int main(int argc, char** argv)
{
    foo(2 == argc ? (int(*)(void*,void*))func1 :
                    (int(*)(void*,void*))func2);

    return 0;
}

void foo(int (*a)(void *, void *))
{
    a((void*)0, (void*)0);
}

3
请注意,这段代码会导致未定义的行为。根据6.5.2.2(9),函数指针类型必须与实际函数兼容。6.7.5.3(15)表明,如果函数具有兼容的返回类型和参数类型,则它们是兼容的。但是,char*int*不兼容,因为6.7.5.1(2)表明,指针类型只有在它们具有相同的限定符并且是指向兼容类型的指针时才是兼容的,而char不兼容于int。[至少存在一种真实的机器,其中sizeof(char*) != sizeof(int*)]。 - Raymond Chen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接