我在用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
我了解回调函数背后的概念,因此我为什么要使用它们实现解耦。如果有人可以澄清我哪里出了问题,我将不胜感激。
谢谢
[使用解决方案进行最终编辑]:更新完成:
首先,再次感谢你们的帮助。 (我最终将在重构中进行typedef的定义,不得不不断重新定义令人讨厌的类型)
这是已完成的代码,可以正常运行。
主机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
不!
<return_type><label>(<f-pointer return_type> * <label>(<parameter>)) //similar to expected normal syntax for a function declaration
-将f指针作为f指针的参数传递需要两件事:
-传递f指针时,传递时不要调用它们。不需要在参数声明或调用中调用它们时都可以调用它们。
-同样,当为具有多个级别的调用传递多个参数时,请记住,它就像一个漏斗一样:您将任何参数传递给函数指针,作为父调用的单独参数。 (因此,重新声明了'const int *模式',然后将其传递给期望const int *的函数)。这适用于多个级别的功能指针,作为其他功能指针的参数。
这些事情只不过是语法错误,只是想当您声明并调用此非常有用的,但最初令人困惑的语言功能时,我会分享一些简单的陷阱。
和平。
答案 0 :(得分:1)
您在尝试传递函数指针时遇到一些问题。看起来您正在传递函数调用的结果,而不是传递函数本身。
以下面这一行为例:
void dw_SpiSetPolAlpha(void (*gpio_setfn)())
这是在声明函数dw_SpiSetPolAlpha
,该函数将指向函数的指针作为参数。指针可以引用为gpio_setfn
,并且必须指向一个返回void并且不带参数的函数。
但是在调用dw_SpiSetPolAlpha
时,您传递的是zg_SetDwSpiPolAlpha(DW_SPI_LPOL_LPHA_MASK)
,这是一个函数调用-所以您传递的是void
,即结果-而不是函数本身。
如果您改为声明void dw_SpiSetPolAlpha(void (*gpio_setfn)(int))
,则可以使用dw_SpiSetPolAlpha(zg_SetDwSpiPolAlpha)
传递函数指针
在dw_SpiSetPolAlpha
中,您可以利用函数指针-并通过调用gpio_setfn(DW_SPI_LPOL_LPHA_MASK)
使用一些typedef进行编辑。 (我不是在编译器之前执行此操作,这太难了,因此可能需要进行一些调整...)
typedef void (*callback)(int);
typedef void (*callback_setter)(callback);
void dw_SpiSetPolAlpha(callback gpio_setfn) {
...
}
void radio_Init(callback_setter radio_spi_polalpha)) {
...
}