【问题标题】:C return function depending on parameterC返回函数取决于参数
【发布时间】:2021-12-30 12:37:36
【问题描述】:

我有一个以回调为参数的函数,它的签名是:

typedef void(*callback_type)(const* uint32_t data, unint8_t size);
void set_callback(callback_type callback);

回调函数所取的两个参数被一个结构体使用,所以我想将回调函数绑定到结构体上。 C++ 有处理这类问题的工具(成员函数、lambdas、std::bind、...)。例如,我试图在 C 中实现的代码等价于 C++ 代码:

set_callback([&](const uint32_t* data, uint8_t size) -> void {
    use_data(&the_struct, data, size);
});

我正在寻找的解决方案有一些要求:

  • 语言:C(或汇编,如果有人愿意的话)
  • 如果可能,不要导入(包括 c 标准库)
  • 独立于编译器(即没有来自 GCC 或 CLang 的 blocks

通过我的研究,我发现了以下代码,但它在我的情况下不起作用并且不真正符合要求,因为它依赖于 gcc 提供的非标准功能(嵌套函数和语句表达式):

#define lambda(lambda$_ret, lambda$_args, lambda$_body)\
({\
lambda$_ret lambda$__anon$ lambda$_args\
lambda$_body\
&lambda$__anon$;\
}) 

还请注意,可以修改代码以在回调中采用 void 指针(作为用户数据),这将解决问题。这是迄今为止我最好的解决方案,可能是最干净的整体。不过,我想要一个不需要这种技巧的解决方案。

即使您只有部分解决方案,我也很乐意听到。

感谢您抽出宝贵时间阅读问题,祝您有美好的一天!

编辑 1: 涉及 lambda 的 c++ 代码不起作用(因为 lambda 捕获...)。为此,必须使用 std::function 或模板化参数。但我认为这一点仍然很清楚。 感谢 tstanisl 指出这一点。

编辑 2: 当我写“被结构使用”时,这实际上是没有意义的。我的意思是:一个函数将使用提供的数据(数据和大小参数)来更新结构的成员并进行一些其他计算。我希望这更清楚。 感谢 '4386427' 和 'Gaurav Pathak' 的 cmets。

【问题讨论】:

  • 将回调绑定到结构体?是否要使用回调更新结构的某些成员,但又不想在回调中使用额外的参数来传递结构的引用?
  • "回调函数取的两个参数被一个结构体使用了..." 没意义...有些代码可以使用结构体但结构体不能使用任何东西
  • 其实C++也没有解决这个问题。 set_callback() 必须是模板函数才能接受 lambda 作为参数

标签: c function lambda


【解决方案1】:

根据您的理解和您的要求,正如您提到的,您不能更改函数原型以添加额外的参数来传递结构的引用,您可以使用全局结构变量,然后您可以在内部使用该全局变量回调函数(希望您可以编辑回调函数或提供自定义回调函数)来更新结构成员(您需要注意同步问题)。

为了解释上面的说法,我在下面提供一个非常简单的例子:

#include<stdio.h>
#include<stdint.h>

typedef struct _the_struct {
    int data;
    int size;
}TheStruct;

TheStruct structVar;

typedef void(*callback_type)(const uint32_t *data, uint8_t size);

void set_callback(callback_type callback);

void my_callback(const uint32_t *data, uint8_t size);

void set_callback(callback_type callback) {
    int a = 5;
    callback(&a, 4);
}

void my_callback(const uint32_t *data, uint8_t size) 
{
    structVar.data = *data;
    structVar.size = size;
    
    printf("Data: %d Size: %d\n", *data, size);
}

int main(void)
{
    set_callback(my_callback);
    
    printf("StructData: %d StructSize: %d\n", structVar.data, structVar.size);
}

我希望解释能为您提供一些有用的信息。

【讨论】:

  • 这就是我目前的解决方案。但我不太喜欢全局变量^^'。
  • 对不起,亲爱的,我不知道如何在不将结构成员作为参数传递或不全局声明的情况下更改结构成员的值。
  • @GauravPathak,这只能在蹦床的帮助下完成。 GCC 将蹦床放在堆栈上。允许将它们放在堆上会更好
  • @tstanisl 在这种情况下,我认为回调函数应该包含一个嵌套函数,该函数以指向结构的指针作为参数,进而操作结构成员值。请纠正我如果我错了,我读了这个答案,stackoverflow.com/a/8179587/2805824
  • @GauravPathak,必须有办法将函数指针转换为指向上下文的指针。 Trampoline 是一种方法,当函数指针的每个实例都有一个指向存储在同一个对象中的上下文的指针时。 GCC 在堆栈上创建一个蹦床,隐式解析上下文。这是非常有限的。在不涉及多线程或递归并且此“lambda”的生命周期完全受控之前,使用全局变量是可以的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-07-18
  • 1970-01-01
  • 2012-07-02
  • 2021-05-13
  • 2021-10-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多