C、【远程过程调用】远程定义和调用函数

如何解决C、【远程过程调用】远程定义和调用函数

我正在编写一个固件,我想在其中定义多个 .c 文件中的函数“命令”,并自动将它们插入函数指针列表中。 随后从串行端口我想调用阵列中存在的这些命令之一, 并使用参数列表执行它。

有一个用于 3d 打印机的固件,我依赖它来实现这样的事情。 https://github.com/KevinOConnor/klipper
使用的软件结构就是这个“远程过程调用”https://en.wikipedia.org/wiki/Remote_procedure_call
在这个固件中,命令在 .ch 文件中实现,.h 中没有原型
例如:

void command_set_digital_out(uint32_t *args)
{
    gpio_out_setup(args[0],args[1]);
}
DECL_COMMAND(command_set_digital_out,"set_digital_out pin=%u value=%c");

以下是所使用的定义列表

// Declare a function to run when the specified command is received
#define DECL_COMMAND_FLAGS(FUNC,FLAGS,MSG)                    \
    DECL_CTR("DECL_COMMAND_FLAGS " __stringify(FUNC) " "        \
             __stringify(FLAGS) " " MSG)
#define DECL_COMMAND(FUNC,MSG)                 \
    DECL_COMMAND_FLAGS(FUNC,MSG)

// Declare a compile time request
#define DECL_CTR(REQUEST)                                               \
    static char __PASTE(_DECLS_,__LINE__)[] __attribute__((used))      \
        __section(".compile_time_request") = (REQUEST)

#define __stringify_1(x)        #x
#define __stringify(x)          __stringify_1(x)

#define ___PASTE(a,b) a##b
#define __PASTE(a,b) ___PASTE(a,b)

随后,当固件获取串行代码时,它能够根据要求调用这些声明的函数。这怎么可能 ?
我无法在我为 platformio 中的 AVR 编写的固件中复制这一点,是否有一种简单且类似的方法来动态声明函数列表?

解决方法

我应该说我根本不喜欢“在数组中自动声明函数”的想法。将数据放在部分是巧妙的技巧,但这只是意大利面条式代码——代码的不同部分通过不可见的链接连接——这可能会导致无法维护的混乱。与其求助于编译器技巧,我建议只在一个地方编写一个大数组,代码清晰、简单、可读和可维护。

是否有一种简单且类似的方法来动态声明函数列表?

这相对非常非常简单。您将按照您希望的方式格式化的数据放入一个部分。 Gcc 编译器从所有文件中选取所有部分并将它们连接起来(假设按随机顺序)并生成符号 - __start_SECTIONAME__end_SECTIONAME,您可以使用它们来迭代该部分中的元素。>

以下代码:

// autofuncs.h ----------------------------------------------------------------------
// a header for the funcionality
#include <errno.h>
#include <string.h>
#include <stddef.h>
#include <assert.h>
#include <stdio.h>

// we'll only need name and a function pointer
struct autofunc_s {
    const char *name;
    int (*main)(int argc,char **argv);
};

// add struct autofunc_s element in section named autofunc
#define AUTOFUNC_ADD(name,func) \
__attribute__((__section__("autofunc"))) \
const struct autofunc_s _autofunc_##func = { name,func };

// a simple runner
// find a function named argv[0] and execute it
static int autofunc_exec(int argc,char **argv) {
    extern const struct autofunc_s __start_autofunc;
    extern const struct autofunc_s __stop_autofunc;
    const struct autofunc_s *it = &__start_autofunc;
    const size_t count = &__stop_autofunc - &__start_autofunc;
    if (argc) {
        for (size_t i = 0; i < count; ++i) {
            if (strcmp(it[i].name,argv[0]) == 0) {
                assert(it[i].main != NULL);
                return it[i].main(argc,argv);
            }
        }
    }
    printf("Command not found\n");
    return ENOENT;
}

// echo.c ----------------------------------------------------------------------
#include "autofuncs.h"
#include <stdio.h>

// example function to run
static int echo(int argc,char **argv) {
    for (int i = 1; i < argc; ++i) {
        printf("%s%s",argv[i],i + 1 == argc ? "\n" : " ");
    }
    return 0;
}
AUTOFUNC_ADD("echo",echo)

// main.c ----------------------------------------------------------------------
// a very very short main that shows the funcionality
#include "autofuncs.h"

int main(int argc,char **argv) {
    // You would possibly here read one line from serial device
    // and tokenize the line on whitespaces here in some loop
    argc--; argv++;
    return autofunc_exec(argc,argv);
}

然后编译并链接:

$ gcc main.c echo.c

你可以:

$ ./a.out something
Command not found
$ ./a.out echo 1 2 3
1 2 3

以同样的方式代替使用 __attribute__((__section__("autofunc"))),您可以制作一个包含所有信息的大型结构数组。

许多编译器对于如何将数据放在一个节中以及如何到达该节有不同的语法。研究你的编译器文档。

请注意,这是一些约定,即带有前导点的部分是相当保留的。对于自定义部分,最好使用没有前导点的部分。

怎么可能?

编译器和链接器公开了一个特定的接口来处理用户定义的部分,允许这样做。

,

我试图寻找一个已经存在的解决方案来实现这个软件结构“远程过程调用”,我找到了这个适用于 arduino 的库:https://simplerpc.readthedocs.io/en/latest/

在这个库中,我可以将通信接口功能定义为远程。
我需要从 C# 命令这个固件!

问题是这个库是用.t​​cc编写和编译的,这是我第一次看到这个扩展。

如果我不能在 tcc 中使用这个库,有人知道类似的库吗?

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-
参考1 参考2 解决方案 # 点击安装源 协议选择 http:// 路径填写 mirrors.aliyun.com/centos/8.3.2011/BaseOS/x86_64/os URL类型 软件库URL 其他路径 # 版本 7 mirrors.aliyun.com/centos/7/os/x86
报错1 [root@slave1 data_mocker]# kafka-console-consumer.sh --bootstrap-server slave1:9092 --topic topic_db [2023-12-19 18:31:12,770] WARN [Consumer clie
错误1 # 重写数据 hive (edu)&gt; insert overwrite table dwd_trade_cart_add_inc &gt; select data.id, &gt; data.user_id, &gt; data.course_id, &gt; date_format(
错误1 hive (edu)&gt; insert into huanhuan values(1,&#39;haoge&#39;); Query ID = root_20240110071417_fe1517ad-3607-41f4-bdcf-d00b98ac443e Total jobs = 1
报错1:执行到如下就不执行了,没有显示Successfully registered new MBean. [root@slave1 bin]# /usr/local/software/flume-1.9.0/bin/flume-ng agent -n a1 -c /usr/local/softwa
虚拟及没有启动任何服务器查看jps会显示jps,如果没有显示任何东西 [root@slave2 ~]# jps 9647 Jps 解决方案 # 进入/tmp查看 [root@slave1 dfs]# cd /tmp [root@slave1 tmp]# ll 总用量 48 drwxr-xr-x. 2
报错1 hive&gt; show databases; OK Failed with exception java.io.IOException:java.lang.RuntimeException: Error in configuring object Time taken: 0.474 se
报错1 [root@localhost ~]# vim -bash: vim: 未找到命令 安装vim yum -y install vim* # 查看是否安装成功 [root@hadoop01 hadoop]# rpm -qa |grep vim vim-X11-7.4.629-8.el7_9.x
修改hadoop配置 vi /usr/local/software/hadoop-2.9.2/etc/hadoop/yarn-site.xml # 添加如下 &lt;configuration&gt; &lt;property&gt; &lt;name&gt;yarn.nodemanager.res