【发布时间】:2019-03-10 22:55:19
【问题描述】:
我正在为 C 中的回调函数而苦苦挣扎。
基本上,我正在尝试编写一些中间件来进行概念验证。我正在使用 Silabs 的 32 位零壁虎和 Decawave 的 UWB 无线电模块。
我正在尝试在开发此代码时考虑到模块化。我想将它与主机系统和选择的无线电脱钩。我想使用它的另一个项目是 wifi 模块,即使通过带有 UWB 模块的 POC,我也不会使用零壁虎。
无论哪种方式,我都试图将 HAL 与中间件分离,然后调用两个 HAL 的任何所需组合。
gpio 功能是必要的,因为在上电时断言所需的线路会设置 spi 极性和 alpha,其他无线模块也是如此。
中间件层:
void radio_Init(void (*radio_spi_polalpha)()){
radio_spi_polalpha();
}
UWB HAL:
/* callback for radio_Init()*/
void dw_SpiSetPolAlpha(void (*gpio_setfn)()){
//call to GPIO lower-level fn
gpio_setfn();
}
主机 HAL:
/* callback for dw_SpiSetPolAlpha()*/
void zg_SetDwSpiPolAlpha(const int mode){
switch (mode){
case 0: gpio->P[PORTC].DOUTSET |= DW_SPI_LPOL_LPHA_MASK;
break;
case 1: gpio->P[PORTC].DOUTSET |= DW_SPI_LPOL_HPHA_MASK;
break;
case 2: gpio->P[PORTC].DOUTSET |= DW_SPI_HPOL_LPHA_MASK;
break;
case 3: gpio->P[PORTC].DOUTSET |= DW_SPI_HPOL_HPHA_MASK;
break;
}
}
应用层调用:
radio_Init(dw_SpiSetPolAlpha(zg_SetDwSpiPolAlpha(DW_SPI_LPOL_LPHA_MASK)));
但我得到的只是“无效使用无效表达式”
不过我不明白,因为我所有的函数都是 void 返回类型。
我胡闹了一会儿,然后尝试了这个:
UWB HAL:
/* callback for radio_Init()*/
void dw_SpiSetPolAlpha(void (*gpio_setfn)(int)){ <-- add int as parameter
//call to GPIO lower-level fn
gpio_setfn();
}
然后我得到“gpio_setfn 的参数太少”,然后我尝试像这样将参数传递给 gpio_setfn():
gpio_setfn(int);
但我只是得到“int之前的预期表达式”
我试过了:
/* callback for radio_Init()*/
void dw_SpiSetPolAlpha(void (*gpio_setfn)(int mode)){ <-- add int as parameter
gpio_setfn(mode);
}
但我只是得到一个隐式声明错误
如果这是重复的,我深表歉意,但我已尽我所能查看有关此问题的尽可能多的线程,但要么似乎没有人回答我的问题,要么我错过了一些重要的线索。研究的线程如下:
Error invalid use of void expression
Error: invalid use of void expression
"Error: invalid use of void expression" when using function as parameter of another[duplicate]
How do you pass a function as a parameter in C
我了解回调函数背后的概念,因此我想使用它们来实现解耦。如果有人可以澄清我哪里出错了,我将不胜感激。
谢谢
[最终编辑解决方案]:完成更新:
首先,再次感谢你们提供的帮助。 (我最终会在重构中对它进行类型定义,不得不不断地重新定义令人讨厌的类型)
这是按预期工作的完整代码。
主机 HAL:
void zg_SetDwSpiPolAlpha(const int* mode){
switch (*mode){
case 0: gpio->P[PORTC].DOUTSET |= DW_SPI_LPOL_LPHA_MASK;
break;
case 1: gpio->P[PORTC].DOUTSET |= DW_SPI_LPOL_HPHA_MASK;
break;
case 2: gpio->P[PORTC].DOUTSET |= DW_SPI_HPOL_LPHA_MASK;
break;
case 3: gpio->P[PORTC].DOUTSET |= DW_SPI_HPOL_HPHA_MASK;
break;
}
}
无线电 HAL:
void dw_SpiSetPolAlpha(void (*gpio_setfn)(const int*), const int* mode){
//call to GPIO lower-level fn
gpio_setfn(mode);
}
中间件:
void radio_Init(void (*radio_spi_polalpha)(void (*)(const int*), const
int*), void (*device_gpio_set)(const int*), const int* mode)
{
radio_spi_polalpha(device_gpio_set, mode);
}
应用调用:
const int one = 1;
radio_Init(dw_SpiSetPolAlpha, zg_SetDwSpiPolAlpha, &one);
对于遇到此问题的其他人需要注意的几点:
-注意 f 指针声明,尤其是作为参数时:这个让我有点吃惊,因为 f 指针标签周围有括号。
带参数的函数:
<return_type> <label>(<f-pointer return_type> (* <label>)( <parameter> )) { } //notice the closing parentheses BEFORE the opening for parameter section. Also note that <label> is optional when declaring a function pointer as a parameter to a function pointer
不!:p>
<return_type><label>(<f-pointer return_type> * <label>(<parameter>)) //similar to expected normal syntax for a function declaration
-将 f 指针作为参数传递给 f 指针,需要两件事:
- 在第一个 f 指针声明中将 f 指针声明为参数
- 您传入的实际函数还必须声明一个 f 指针作为参数
-当你传递 f 指针时,不要在传递它们时调用它们。在需要调用它们时调用它们,无论是在参数声明中还是在调用中。
- 同样,当为具有多个级别的调用传递多个参数时,请记住它的工作原理就像一个漏斗:您将任何参数作为父调用的单独参数传递给函数指针。 (因此重新声明了“const int* 模式”,然后将其传递给期望 const int* 的函数)。这适用于作为其他函数指针参数的多级函数指针。
这些东西只不过是语法错误,但只是想我会分享一些简单的陷阱,以便在您声明和调用这个非常有用但最初令人困惑的语言功能时注意。
和平。
【问题讨论】:
-
您可以在这里找到处理此问题的好方法:techtalk.intersec.com/2014/11/blocks-rewriting-with-clang
-
我建议为您的回调使用
typedef,例如:typedef void (*callback)(void);。 -
我一定会研究这两种解决方案......这块东西看起来很酷。在我开始进一步抽象之前,我绝对想把这个原始概念放在我的脑海里。我的大脑目前正在变成糊状。
标签: c callback embedded function-pointers