【问题标题】:Function pointer to different functions with different arguments in C指向C中具有不同参数的不同函数的函数指针
【发布时间】:2013-05-22 03:55:27
【问题描述】:

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

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 编译器/链接器

【问题讨论】:

  • 将函数指针设为void *,然后在调用时进行正确的类型转换?但是,您会失去各种类型的安全性。

标签: c function-pointers


【解决方案1】:

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

没有。 (除了脏的类型转换。)

还有其他方法吗?

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

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

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

【讨论】:

    【解决方案2】:

    您的理解是正确的。
    函数指针的签名必须与相应的函数匹配。

    考虑learncpp.com

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

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

    *pFoo 周围的括号是必要的,因为 int *pFoo() 将被解释为一个名为 pFoo 的函数,它不接受任何参数并返回一个指向整数的指针。

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

    ...

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

    【讨论】:

    • 好吧,实际上pFoo 是一个指向函数的指针,该函数可以接受任意数量的任何类型的参数。见godbolt.org/z/Y8M3jP
    【解决方案3】:

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

    【讨论】:

      【解决方案4】:

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

      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_1false 知道它应该假设condition_2。注意 union 是按值传递的;毕竟它只是一个大小的函数指针,所以这并不比将指针传递给它更昂贵。

      【讨论】:

        【解决方案5】:

        一个类型转换方法的示例,用于对不同原型的不同函数使用相同的函数指针。

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

        【讨论】:

        • 您能否添加对您所做工作的描述?而不是仅仅粘贴代码。
        【解决方案6】:

        一个老话题,但我面临同样的问题,终于有了这个想法。

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

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2017-03-26
          • 1970-01-01
          • 1970-01-01
          • 2020-07-03
          • 1970-01-01
          • 2011-04-03
          • 1970-01-01
          相关资源
          最近更新 更多