【问题标题】:C void* function pointer argumentC void* 函数指针参数
【发布时间】:2015-09-07 11:01:33
【问题描述】:

我正在尝试在 ARM 中创建一个任务队列。基本思路如下。

typedef void (*funcpointer)(void *);     // the argument being passed will be a void pointer that I can hopefully typecast

struct sQueue{
   funcpointer       func_address;        // this stores the address of the function to be called
   void              *func_parameter;                   // this stores the address of the struct that is passed to the function
   uint32_t          TimeStamp;                  // the time at which the function should be called     
};

sQueue Func_List[10];

计划是能够将应该调用的函数的地址放在Func_List[x].func_address中。

我希望能够将接受指向不同结构类型的指针的函数的地址放在 func_address 中。 这是一个例子:

void Config_ADC(sADC_Settings *pSettings);

void Enable_RX(sRX_Top_Settings *pSettings);

这两个函数都有效地接受一个指向结构的 32 位指针,但在这些情况下,结构是不同的类型。

当我尝试分配 Func_List[x].func_address = Config_ADC 时,编译器会抱怨:

“void (*)(sADC_Settings *)”类型的值不能分配给“funcpointer”类型的实体

关于如何实现这一目标的任何想法?我当然可以将函数 Config_ADC 更改为接受 void* 指针,然后在函数内部进行类型转换,但我真的不想这样做。

【问题讨论】:

    标签: c function-pointers


    【解决方案1】:

    IIRC 通过具有不同签名的函数指针调用函数是 UB。

    对于每个不匹配的函数类型,您都需要一个代理函数。

    void Config_ADC(sADC_Settings *pSettings);
    void Config_ADC_proxy(void *pSettings){
      Config_ADC((sADC_Settings*) pSettings);
    }
    

    【讨论】:

    • 有趣的是,它似乎与 Func_List[0].func = (funcpointer)Config_ADC;新问题是 Config_ADC 实际上是一个类的成员函数,当我尝试执行 Func_List[1].func = (funcpointer)DrvRX1.Config_ADC;我收到错误“指向绑定函数的指针可能仅用于调用函数”,这是预期的,因为在调用函数时它必须知道 THIS 指针,是否有这个?
    • @EoinOConnell 这仍然是未定义的行为。您是在告诉编译器将您拥有的函数指针转换为另一种类型,但您仍将通过不同类型的指针进行调用。
    • C 没有成员函数的概念。请使用C++ 标签添加一个新问题。我会避免扩展这个问题,因为它涵盖了一个完全不同的主题。此外,这个问题不是关闭的下一个目标,因为它之前已经回答过很多次了。最好的方法是搜索并找到这样的内容:stackoverflow.com/questions/23184662/call-member-function
    【解决方案2】:

    一种解决方案是在函数内部强制转换 void 指针:

    void Config_ADC(void *p)
    {
        sADC_Settings *pSettings = (sADC_Settings *)p;
    

    (其实我不喜欢这样,因为它不必要地占用了另一个变量,但是,我认为它已经比涉及堆栈管理和调用管理开销的代理函数更好。当void * 是参与;那么根本不会有任何开销。)

    【讨论】:

    • 您在这里假设他仍然可以更改 Config_ADC 功能。如果不是这样,他必须使用代理功能才能获得 UB 免费。
    【解决方案3】:

    您特定的ABI 规范(特定于目标处理器、操作系统,甚至可能是编译器)规定了如何调用C 函数以及使用哪个calling conventions。请注意,某些形式参数可能会通过某些硬件寄存器传递。

    我建议使用typedef-s 来定义称为直通指针的函数的任何签名:

    typedef void myroutofint_t(int);
    typedef int  myintof2int_t (int, int);
    

    如果您确定被调用函数的签名,并且可以列出通过指针调用的函数的所有签名,则可以使用未命名的联合(在 C99 或 C11 中):

    struct sQueue{
     enum functiontype_en funtype;
     union {
       void* funaddress;
       myroutofint_t *funroutofint;
       myintof2int_t *funintof2int;
     };
     // othe fields of SQueue
     };
    

    C 标准甚至不要求函数指针和数据指针位于相同的地址空间并具有相同的大小。但 POSIX 确实如此,而且我们假设是这样。

    顺便说一句,您可能需要libffi

    【讨论】:

      猜你喜欢
      • 2015-04-18
      • 1970-01-01
      • 1970-01-01
      • 2020-06-11
      • 1970-01-01
      • 2018-04-19
      • 2011-07-31
      • 2012-12-17
      • 2019-04-13
      相关资源
      最近更新 更多