【问题标题】:Invalid use of void expression callback function无效表达式回调函数的使用无效
【发布时间】: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 指针,需要两件事:

  1. 在第一个 f 指针声明中将 f 指针声明为参数
  2. 您传入的实际函数还必须声明一个 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


【解决方案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 void (*callback)(int);
typedef void (*callback_setter)(callback);

void dw_SpiSetPolAlpha(callback gpio_setfn) {
...
}

void radio_Init(callback_setter radio_spi_polalpha)) {
...
}

【讨论】:

  • 我明白了...我刚刚尝试这样做,但仍然有同样的错误。我会在我的 OP 中更新。
  • 我是在给你举个例子,并没有解决所有的问题。您对radio_Init 的调用也有同样的问题,它需要一个指向没有参数的函数的指针。但是你从一个带有参数的函数传递给它一个函数调用......肯定会进入一些typedefs 会帮助你的领域。
  • 哈哈抱歉,这不应该是一个刻薄的评论......好吧,我刚刚意识到我在这里的参数方面正在做什么。好的很酷,非常感谢,我不敢相信我没有看到这个。显然该睡觉了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-11-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多