17

我有两个具有可变数量和类型的参数的函数

double my_func_one(double x, double a, double b, double c) { return x + a + b + c }
double my_func_two(double x, double p[], double c) { return x + p[0] + p[1] + c }

我想使用一个指向我上面定义的函数的函数的指针,基于某个条件变为真,例如

if (condition_1)
   pfunc = my_func_one;
else if (condition_2)
   pfunc = my_func_two;

 // The function that will use the function I passed to it
 swap_function(a, b, pfunc);

我的问题是,对于这种情况,我可以定义一个函数指针吗?如果是,如何?
我的理解是函数指针的原型对于它可以指向的所有函数都应该是相同的。

typedef double (*pfunction)(int, int);

就我而言,它们不一样。有没有其他方法可以做到这一点?

语言

我正在用 C 开发,我正在使用 gcc 4.4.3 编译器/链接器

4

6 回答 6

29

最干净的方法是使用联合:

typedef union {
  double (*func_one)(double x, double a, double b, double c);
  double (*func_two)(double x, double p[], double c);
} func_one_two;

然后你可以初始化联合的一个实例,并在swap_function函数中包含信息来说明哪个字段是有效的:

func_one_two func;

if (condition_1)
   func.func_one = my_func_one;
else if (condition_2)
   func.func_two = my_func_two;

 // The function that will use the function I passed to it
 swap_function(a, b, func, condition_1);

该假设swap_function基于它应该假设condition_1是可以知道的。注意 union 是按值传递的;毕竟它只是一个大小的函数指针,所以这并不比传递一个指针更昂贵。falsecondition_2

于 2013-05-27T10:16:58.887 回答
13

我的问题是,对于这种情况,我可以定义一个函数指针吗?

不。(除了肮脏的类型转换。)

有没有其他方法可以做到这一点?

最好的办法是为现有函数之一创建一个包装函数。例如:

double my_func_one_wrapper(double x, double p[], double c) {
    return my_func_one(x, p[0], p[1], c);
}

这样,您就有两个具有相同签名的函数,因此具有相同的函数指针类型。

于 2013-05-27T10:02:31.937 回答
2

一个古老的话题,但我面临同样的问题,最终提出了这个想法。

如果您希望每个函数都使用相同的原型,您可以将参数包装在如下结构中:

 typedef struct {
     double a,
            b,
            c; 
 }chunk1_t;

  typedef struct {
     double p[];
     double c; 
 }chunk2_t;

然后你的函数指针变为:

 double (*pfunc) (double x, void *args);

这导致了这样的事情:

 pfunc cb;

 double swap_function(double x, pfunc cb, void *args);

 double my_func_one(double x, void *args) { 
   chunk1_t *chunk = (chunk1_t*) args;
   return x + chunk->a + chunk->b + chunk->c; 
 }

 double my_func_two(double x, void *args) {
   chunk2_t *chunk = (chunk2_t*) args;
   return x + chunk->p[0] + chunk->p[1] + chunk->c ;
 }

 int main(){
   // declare a, b,...
   double a = 1.0f;
   //...
   // cast for safety
   chunk1_t myChunk1 = {(double)a, (double)b, (double)c};
   // don't if you like risk
   chunk2_t myChunk2 = {p, c};

   swap_function(x, cb, &myChunk1); 
   swap_function(x, cb, &myChunk2);
 }

使用存储在结构中的函数指针:

 #define FUNC_ONE_METHOD 1
 #define FUNC_TWO_METHOD 2

 typedef struct chunk{
     double a, b, c;
     double p[];
     int method;
     double (*pfunc) (double x, struct chunk *self);
 }chunk_t;

 double swap_function(double x, chunk_t *ch){
    switch (ch->method)
    {
        case FUNC_TWO_METHOD:
            ch->pfunc = my_func_two;
            break;
        case FUNC_ONE_METHOD:
            ch->pfunc = my_func_one;
            break;
        default:
            return -1; // or throw error
    return ch->pfunc(x, ch);
 }


 chunk c = {.a= 1, .b=3, .c=1, .method=1};
 swap_function(x, &c);
于 2020-05-26T17:09:53.907 回答
1

你的理解是对的。
函数指针的签名必须与相应的函数匹配。

考虑learncpp.com

就像可以声明一个指向变量的非常量指针一样,也可以>声明一个指向函数的非常量指针。这样做的语法是你将看到的最丑陋的事情之一:

// pFoo is a pointer to a function that takes no arguments and returns an integer 
int (*pFoo) (); 

由于优先级原因, *pFoo 周围的括号是必需的,因为 int*pFoo()将被解释为一个名为的函数pFoo,它不带参数并返回一个指向整数的指针。

在上面的代码片段中,pFoo是一个指向没有参数并返回整数的函数的指针。pFoo可以“指向”与此签名匹配的任何函数。

...

请注意,函数指针的签名(参数和返回值)必须与函数的签名匹配。

于 2013-05-27T10:02:56.570 回答
1

你想要什么是可能的,但有点脏。函数指针可以相互转换而不会丢失信息。重要的是,您总是必须通过这样一个指针调用一个函数,只有一个与其定义相对应的签名。因此,如果您在调用函数之前回退并使用正确的参数进行调用,那么一切都应该没问题。

于 2013-05-27T10:10:47.760 回答
-2

对不同原型的不同函数使用相同函数指针的类型转换方法示例。<>

#include <stdio.h>
typedef void (*myFuncPtrType) (void);

typedef int (*myFunc2PtrType)(int, int);

typedef int * (*myFunc3PtrType)(int *);

static void myFunc_1 (void);
static int myFunc_2 (int, int);
static int* myFunc_3 (int *);

const myFuncPtrType myFuncPtrA[] = {
                                    (myFuncPtrType)myFunc_1,
                                    (myFuncPtrType)myFunc_2,
                                    (myFuncPtrType)myFunc_3
};

static void myFunc_1 (void)
{
    printf("I am in myFunc_1 \n");
}

static int myFunc_2 (int a, int b)
{
    printf("I am in myFunc_2\n");
    return (a+b);
}

static int* myFunc_3 (int *ptr)
{
    printf("I am in myFunc_3\n");
    *ptr = ((*ptr) * 2);
    return (ptr+1);
}

int main(void) {
    // your code goes here
    int A[2],C;

    int* PTR = A;

    (*(myFuncPtrA[0]))();

    A[0]=5;
    A[1]=6;

    C = ((myFunc2PtrType)(*(myFuncPtrA[1])))(A[0],A[1]);

    printf("Value of C: %d \n", C);

    printf("Value of PTR before myFunc_3: %p \n", PTR);
    printf("Value of *PTR before myFunc_3: %d \n", *PTR);

    PTR = ((myFunc3PtrType)(*(myFuncPtrA[2])))(&A);

    //Lets look how PTR has changed after the myFunc_3 call

    printf("Value of PTR after myFunc_3: %p \n", PTR);
    printf("Value of *PTR after myFunc_3: %d \n", *PTR);


    return 0;
}
于 2017-04-25T12:17:33.597 回答