使用不同指针类型作为参数来投射函数指针

问题描述:

我想,下面的代码描述了我正在尝试做的事情。具体来说,我希望将一个函数指针转换为泛型函数类型,唯一不同的是签名是不同的指针类型。使用不同指针类型作为参数来投射函数指针

现在,我知道有一个功能指针需要兼容,this question讨论,但我不确定是否有不同的指针类型的参数是否满足兼容性要求。

代码编译并运行,但如预期的那样,将给出关于不兼容指针类型的赋值的警告。有什么方法可以满足编译器并实现我所追求的目标?

#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; 
} 

最简洁的方式是恕我直言,演出里面的功能。这将强制所有的功能签名是相同的,并保持从调用者的代码转换。 (这是例如qsort()想要的方式)

int double_function(void *p, unsigned size) 
{ 
    double *array = p  
    unsigned uu; 

    for(uu=0; uu < size; uu++){ 
     printf("%f\n", array[uu]); 
    } 
return 42; 
} 
+0

的确,我曾考虑过这个问题。问题在于我打电话给一个图书馆(它本身可能有一堆问题!)。因此,我需要将每个要调用的函数分别包装起来,这就是我试图避免的(尽管它仍然保持内部逻辑简单)。 – 2012-01-28 13:32:26

+0

我没有想到库函数的情况。很难保持编译器和读者的快乐。也许包装函数(或丑陋的预处理器 - 黑客;-)是正确的方法。 – wildplasser 2012-01-28 13:39:26

+0

我同意一个包装函数是最干净的方法。多一点代码,但它有一个很好的逻辑分离。它还允许我更改签名并在包装器中包含代码。 – 2012-01-28 16:58:26

编辑:由于@Mat指出,遵循C规范,你需要调用它之前投的函数指针回到原来的类型,这将使​​得这整个锻炼; Tibial相当少一点有用;

((int(*)(float*,int))generic_function)(a, 5); 

另一种解决方案(通过从@wildplasser答案启发)是包装的功能中的功能服用无效*以及执行对参数的铸造来代替。这样做“通过宏观”非常简单;

#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); 

这就是说,指针转换通常不是我主张的解决方案,但它有它的用例。

+1

这只是关闭了编译器(隐藏地毯下的问题)。不好的建议IMO。 – Mat 2012-01-28 13:28:36

+0

编译器不应该被关闭的技术是否存在固有的问题? – 2012-01-28 13:29:36

+1

是的,你在不兼容的函数指针类型之间进行投射,并调用投射函数而不会将其转换回其真实类型。根据标准,这是未定义的行为。 – Mat 2012-01-28 13:31:47

是的,声明它没有原型。

int (*generic_function)() = NULL; 

现在你可以指定一个返回int任何功能,而且还可以通过任何参数,并且不需要编译器不兼容拒绝参数。

+0

但是,这样做的缺点是,如果您尝试使用指向strcmp()或fprintf()的指针作为函数指针,编译器不会抱怨。 – wildplasser 2012-01-28 13:46:34

+0

@wildplasser与使用'void *'作为参数类型时的问题相同。当它在body中需要'double *'等时,你仍然可以传递一个'int *'。 – 2012-01-28 14:06:11

+0

是的,这是正确的。但是编译器*至少可以检查一个指针和一个int是否作为参数传递。 – wildplasser 2012-01-28 14:09:38