如何为静态嵌入式操作系统创建一个复杂的宏资源检查?

4

我有一个嵌入式操作系统,需要在编译时静态定义其资源。

例如:

#define NUM_TASKS 200

目前,我有一个头文件,每个开发者都需要声明他/她所需的任务,就像这样:

#define ALL_TASKS  ( \
                     1 + \  /* need one task in module A */
                     2   \  /* need two tasks in module B */
                   )

在操作系统编译期间,会进行一项检查:

#if (ALL_TASKS > NUM_TASKS)
#error Please increase NUM_TASKS in CONF.H
#endif

当我编译时,需要更多的任务,编译就会停止,并明确告知静态操作系统没有足够的任务来使其工作。

目前为止还好。


懒惰的程序员忘记将他在模块A中添加的任务添加到目录x/y/z/foo/bar/baz/中的全局声明文件中。

我想要的是以下构造,但我似乎无法通过任何宏技巧实现:

使用宏声明模块中所需的资源,如下所示:

OS_RESERVE_NUMBER_OF_TASKS(2)

在这个模块中,将全局任务数量增加2。

我的第一个粗略想法是这样的:

#define OS_RESERVE_NUMBER_OF_TASKS(max_tasks)       #undef RESOURCE_CALC_TEMP_MAX_NUM_TASKS \
                                                    #define RESOURCE_CALC_TEMP_MAX_NUM_TASKS    RESOURCE_CALC_MAX_NUM_TASKS + max_tasks \
                                                    #undef RESOURCE_CALC_MAX_NUM_TASKS  \
                                                    #define RESOURCE_CALC_MAX_NUM_TASKS     RESOURCE_CALC_TEMP_MAX_NUM_TASKS    \
                                                    #undef RESOURCE_CALC_TEMP_MAX_NUM_TASKS

但是这样做行不通,因为在一个#define中嵌套另一个#define是无效的。
所以问题基本上是:
您有想法如何将任务数量的计算拆分到多个文件(即模块本身)中,并在编译时将该数字与定义的最大任务数进行比较吗?
如果这不能通过纯C预处理器解决,那么我必须等到我们更改构建系统为scons...

我不相信在纯C中这是可能的,因为它需要在翻译单元(C文件/模块)之间传递预处理信息。 - Drew McGowen
2
如果C11是一个选项,而你只想让编译失败,你可能可以使用static_assert而不必使用奇怪的预处理器技巧。 - Drew McGowen
2个回答

3

你能要求任务具有某些ID或类似的标识,所有任务用户必须使用它们吗?

tasks.h

enum {
    TASK_ID_TASK_A_1,
    TASK_ID_TASK_B_1,
    TASK_ID_TASK_B_2,
    NUM_TASKS
};
void * giveResource(int taskId, int resourceId);

user_module_B.c

#include "tasks.h"
...
resource = giveResource(TASK_ID_TASK_B_1, resource_id_B_needs);

好主意。这将使开发人员注意资源的使用,因为他们不能在枚举中声明其ID之前简单地创建另一个资源。 - TabascoEye
@TabascoEye 如果你想将其他数据与ID号码关联起来,你可能会发现这里的技巧很有用。链接 - user694733

1
您可以使用 Boost Preprocessor 库的 评估插槽功能 在翻译一个单元的过程中更新宏的值。它定义了几个“插槽”,可以被预处理器代码视为可变全局变量,这将使您能够逐步添加值,而不是用单个表达式定义它。
(这是纯标准 C,但实现它的代码相当复杂)
由于依赖于调用 #include,所以不能在一行中完成,这意味着您不能将其封装成漂亮的一行宏,但它看起来会像这样:
#define TASK_SLOT 2    //just pick one
#define ALL_TASKS BOOST_PP_SLOT(TASK_SLOT)

#define BOOST_PP_VALUE 1 + 2
#include BOOST_PP_ASSIGN_SLOT(TASK_SLOT)    // ALL_TASKS now evals to 3

#define BOOST_PP_VALUE 3 + ALL_TASKS
#include BOOST_PP_ASSIGN_SLOT(TASK_SLOT)    // ALL_TASKS now evals to 6

如Drew所说(我可能误解了您的要求),这仅适用于一个翻译单元。如果您有一个中央NUM_TASKS,并且允许每个单元累加其自己的ALL_TASKS数字,则可以使用。
如果您需要在多个.c文件中增加值(以便最终的ALL_TASKS是所有模块的总和,而不是一个模块的总和),则需要将它们封装到unity build中,以使此技术起作用,但大多数人认为这是一个坏主意。更先进的构建系统可能更合适,因为预处理器仅设计用于单个单元。

可以使用Boost来实现这个目的吗?它是一个C++库/框架,但是给出的问题标记为C。 - Drew McGowen
在这种情况下,是的,它的PP库符合C规范。 C++没有添加任何内容到预处理器中。 - Alex Celeste

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接