C 将具有不同指针类型的函数指针转换为参数

C 将具有不同指针类型的函数指针转换为参数,c,function-pointers,C,Function Pointers,我认为下面的代码描述了我正在尝试做的事情。具体来说,我希望将函数指针强制转换为泛型函数类型,签名的唯一区别是指针类型不同 现在,我知道函数指针有一个兼容性要求,如中所述,但我不确定具有不同指针类型的参数是否满足该兼容性要求 代码会编译并运行,但正如预期的那样,会从不兼容的指针类型发出有关赋值的警告。有什么方法可以让编译器满意并实现我想要的吗 #include <stdio.h> int float_function(float *array, int length) { i

我认为下面的代码描述了我正在尝试做的事情。具体来说,我希望将函数指针强制转换为泛型函数类型,签名的唯一区别是指针类型不同

现在,我知道函数指针有一个兼容性要求,如中所述,但我不确定具有不同指针类型的参数是否满足该兼容性要求

代码会编译并运行,但正如预期的那样,会从不兼容的指针类型发出有关赋值的警告。有什么方法可以让编译器满意并实现我想要的吗

#include <stdio.h>

int float_function(float *array, int length)
{
    int i;
    for(i=0; i<length; i++){
        printf("%f\n", array[i]);
    }
}

int double_function(double *array, int length)
{
    int i;
    for(i=0; i<length; i++){
        printf("%f\n", array[i]);
    }
}


int main() 
{
    float a[5] = {0.0, 1.0, 2.0, 3.0, 4.0};    
    double b[5] = {0.0, 1.0, 2.0, 3.0, 4.0};

    int (*generic_function)(void*, int) = NULL;

    generic_function = &float_function;
    generic_function(a, 5);

    generic_function = &double_function;
    generic_function(b, 5);

    return 0;
}
#包括
整数浮点_函数(浮点*数组,整数长度)
{
int i;

对于(i=0;iEDIT):正如@Mat所指出的,要遵循C规范,需要在调用函数指针之前将其转换回原始类型,这将使整个练习变得不那么有用

((int(*)(float*,int))generic_function)(a, 5);
另一个解决方案(受@wildplasser答案的启发)是将函数包装在函数中,取void*并对该参数执行强制转换

#define WRAP(FN, TYPE) int FN##_wrapped(void* p, int len) { return FN((TYPE*)p, len); }
WRAP(float_function, float)
WRAP(double_function, double)
然后,您可以使用以下相当干净的线条

generic_function = float_function_wrapped;
generic_function(a, 5);

也就是说,指针强制转换通常不是我提倡的解决方案,但它有自己的用例。

最干净的方法是在函数内部执行强制转换。这将强制所有函数签名相同,并将强制转换排除在调用方的代码之外。(例如,这是qsort()所希望的方式)

int-double_函数(void*p,无符号大小)
{
双*数组=p
无符号uu;
对于(uu=0;uu
是,在没有原型的情况下声明它

int (*generic_function)() = NULL;

现在,您可以分配任何返回
int
的函数,但也可以传递任何参数,并且编译器不需要拒绝不兼容的参数。

这只会关闭编译器(隐藏问题).我的建议不太好。编译器不应该关闭的技术是否存在固有问题?是的,您正在不兼容的函数指针类型之间进行强制转换,并调用强制转换函数,而没有将其强制转换回其实际类型。根据标准,这是未定义的行为。@Mat更新了答案,考虑将其删除,但您提供的e信息非常有用(至少对我来说是新的),这也是一个很好的解决方案。我不想使用宏还有其他原因,但在另一种情况下,这会很好。事实上,我已经考虑过了。问题是我正在调用一个库(它本身可能有一大堆问题!).因此,我需要分别包装我正在调用的每个函数,这是我试图避免的(尽管它仍然保持了内部逻辑的简单)。我没有想到库函数的情况。这将很难让编译器和人类读者都满意。可能是包装函数(或丑陋的预处理器黑客;-)是正确的方法。我同意包装函数是最干净的方法。代码多一点,但它有一个很好的逻辑分隔。它还允许我更改签名并在包装中包含代码。但这样做的缺点是,如果您尝试使用指向strcmp()或fprintf()的指针,编译器不会抱怨作为函数指针。@wildplasser这与使用
void*
作为参数类型时遇到的问题完全相同。当一个
int*
在主体中需要一个
double*
之类的参数时,您仍然可以传递它。是的,这是正确的。但是编译器至少可以检查一个指针和一个int是否作为参数传递。这不是根据规范未定义?
int (*generic_function)() = NULL;