【问题标题】:Function pointer with undetermined parameter带有未确定参数的函数指针
【发布时间】:2012-07-19 14:17:55
【问题描述】:

我想要一个可以接受各种类型参数的函数指针。我该怎么做?

以下示例(第 1 行),我希望 void (*fp)(int) 也能够采用 void (*fp)(char*)。以下代码无法正确编译,因为我在预期 int 的地方传递了 char*,因此编译以下代码会给您警告(并且无法正常工作)。

void callIt(void (*fp)(int))
{
    (*fp)(5);
}

void intPrint(int x)
{
    printf("%d\n", x);
}

void stringPrint(char *s)
{
    printf("%s\n", s);
}

int main()
{
    void (*fp1)(int) = intPrint;
    callIt(fp1);
    void (*fp2)(char*) = stringPrint;
    callIt(fp2);
    return 0;
}

注意:我知道尝试将整数 5 作为 char* 参数传递是愚蠢的,但这不是这个问题的关注点。如果需要,可以将 char* 替换为 float。

【问题讨论】:

  • 你不会在 C 中得到你想要的。你可以在 C++ 中使用模板来做到这一点。在 C 语言中,您需要针对不同类型使用不同的 callIt 函数。
  • int(5) 如何是floatPrint(float f) 的有效参数?您需要进行强制转换,但如果您通过强制转换删除了函数指针类型,这将不起作用。

标签: c function-pointers


【解决方案1】:

我会说使用void (*fp)(void*),然后传入指向变量的指针并将它们转换为void*。这很 hacky,但它应该可以工作。

例如:

void callIt(void (*fp)(void*))
{
    int x = 5;
    (*fp)((void*)&x);
}

【讨论】:

  • 但这并不理想。你真的应该考虑重新设计程序,这样你就不必求助于这种骇人听闻的方法。 :)
  • 注意 int x = 5 强制类型为 int :(
  • 为了减少hacky,理论上你可以使用一个结构,它是可能类型的联合,并传递一个指向它的指针,加上一个变量来显示数据类型。更多的工作并使代码复杂化,但会使它看起来更像是一个“正确”的解决方案。 :)
【解决方案2】:

您希望对 stringPrint 的调用究竟能做什么?

看起来好像你确实得到了这个工作,它最终会尝试将内存位置 5 的内容打印为字符串。我怀疑这不是你想要的,因为它会崩溃,我怀疑你打算输出 '5'。

还要注意 ... 至少需要一个命名参数。传递一个 void * 和大量的强制转换至少可以编译。

【讨论】:

    【解决方案3】:

    虽然不是很好,但函数指针的类型并不重要。

    只要定义为

    typedef void (*fp_t)(void * pv);
    

    您唯一需要确保的是您调用它的方式与您分配给它的功能相匹配。

    int intFuncWithTwoDoubles(double d1, double d2);
    char * pCharFuncWithIntAndPointer(int i, void * pv);
    
    ...
    
    fp_t fp = NULL;
    
    fp = intFuncWithTwoDoubles;
    printf("%d", fp(0.0, 1.0));
    
    fp = pCharFuncWithIntAndPointer;
    printf("%s", fp(1, NULL));
    
    ...
    

    【讨论】:

    • 我不是 C 标准专家,但这看起来很 hacky,可能是未定义的行为,我绝对喜欢它,因为它完全无视类型安全。基本上,您依赖于编译器安排您在调用时设置的任何参数和返回值,而不是使用函数指针的类型。你真的试过这个吗?它产生了哪些警告、错误和/或结果?
    • @KevinVermeer:是的,看起来像一个肮脏的黑客。但是:它可以工作,尽管在将函数地址分配给指针时会产生有关类型不匹配的警告。但据我的调查显示,它确实不会导致未定义的行为(我将在今天晚些时候尝试挖掘出这方面的标准)。
    【解决方案4】:

    你为什么不把它变成一个接受 void* 参数的函数指针?

    void(*fp)(void*) 
    

    这将处理所有可能的指针参数。现在对于数据类型,您可以为每个函数创建一个函数指针类型,或者只为将要与函数指针一起使用的函数创建一个函数指针类型,将数据类型作为指针传递并在函数的开头取消引用它们。这只是一个想法,不知道你想做什么。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-01-03
      • 2018-08-25
      • 2019-09-16
      • 2015-09-03
      • 1970-01-01
      • 2012-01-04
      • 2014-04-14
      • 2019-10-20
      相关资源
      最近更新 更多