gpt4 book ai didi

c - 使用 X 列表和预处理器指令在编译时生成可配置的 C 代码

转载 作者:行者123 更新时间:2023-11-30 16:57:50 26 4
gpt4 key购买 nike

我的代码库已经包含重复的代码,只有细微的差别、可序列化的 ID、索引、变量数组。

代码库巨大,一些组件根据简单的预处理器指令和常量激活/停用(例如:#define CFG_PROJECT cfgAutobot#define CFG_PROJECT cfgUltron、 ..等)。

功能实际上是相同的,但组件和条件不同。示例:

int somedata;
int somecounter;

void main_loop(){
#if(CFG_PROJECT == cfgAutobot)
if(someInterface() == 1){
somedata = some_other_interface();
}
#endif

#if(CFG_PROJECT == cfgUltron)
if(third_if() > 0){
someCounter++;
}
else
{
someCounter = 0;
}
#endif
}

void query_data(int selector){
if(False){
/* Dummy block */
}
#if(CFG_PROJECT == cfgUltron)
else if(selector == 1){
return somedata;
}
#endif
#if(CFG_PROJECT == cfgAutobot)
else if(selector == 2){
return someCounter;
}
#endif
else{
return Err_code;
}
}

由于此代码处理的数据比简单的计数器和整数要复杂得多,涉及不同大小的多个组件,因此这些代码部分要复杂得多。然而,它们可以追溯到一个共同的结构。

我能够应用 X-list 技术,如下所示:

#define Ultron_implementation X(var_ultron, (someInterface() == 1), update_function_1, selector_id_1)
#define Autobot_implementation X(var_autobot, (third_if() > 0), update_function_2, selector_id_2)

/* (Please note, that this is a simplified example, in the actual
code there are much more components, but the `main_loop`
implementation can be traced back to a few update functions) */
void update_function_1(int var, int selector) {
if(selector == 1){
var++;
}else{
var = 0;
}
}


void update_function_2(int var, int selector) {
if(selector == 1){
var = some_other_interface();
}else{
/* Nothing to do */
}
}

#define X(var_name,condition,func_name,sel_id) int var_name;
Ultron_implementation
Autobot_implementation
#undef X

void main_loop(){

#define X(var_name,condition,func_name,sel_id) \
if(condition){ \
func_name(var_name, true);\
}else{ \
func_name(var_name, false);\
}
Ultron_implementation
Autobot_implementation
#undef X
}

void query_data(int selector){
if(False){
/* Dummy block */
}
#define X(var_name,condition,func_name,sel_id) \
else if(selector == sel_id){ \
return var_name;\
}
Ultron_implementation
Autobot_implementation
#undef X

else{
return Err_code;
}
}

这样做的问题是,尽管现在是统一的实现,但新组件的引入仍然需要复制粘贴,并通过先前定义的常量进行过滤(即:CFG_PROJECT ) 现在已从逻辑中排除。

<小时/>

有没有一种方法可以最大限度地减少复制粘贴到代码中各个位置的需要并根据定义的常量(即CFG_PROJECT)进行过滤?

最佳答案

在编译时过滤预定义常量需要预处理器指令#if#ifdef等。但无法在内部使用这些指令#define 语句据我所知。

但是在 #define 语句之外编写这些内容是完全合法的。

#if(CFG_PROJECT == cfgAutobot)
#define Autobot_implementation X(var_autobot, (third_if() > 0), update_function_2, selector_id_1)
#else
#define Autobot_implementation
#endif

#if(CFG_PROJECT == cfgUltron)
#define Ultron_implementation X(var_autobot, (third_if() > 0), update_function_2, selector_id_2)
#else
#define Ultron_implementation
#endif

前者可以编译成一个列表(多种)

#define MACRO_LIST \
Autobot_implementation \
Ultron_implementation

根据定义的常量,MACRO_LIST 的元素将包含 X() 函数定义(即:实现)或空常量。

现在在实现中可以使用以下内容:

void main_loop(){

#define X(var_name,condition,func_name,sel_id) \
if(condition){ \
func_name(var_name, true);\
}else{ \
func_name(var_name, false);\
}
MACRO_LIST
#undef X
}

要总结已激活的组件,查看有多少组件被激活并在实现中引用它们,可以使用连接 (##) 标记,例如枚举定义。示例:

#define X(var_name,condition,func_name,sel_id) var_name ## index, 
tyepdef enum{
MACRO_LIST
components_end
}component_index;
#undef X

some_struct COMPONENT_FLAGS[components_end];

基本上任何相关的变量、ID 或实现都可以通过这种方式“序列化”。

请注意:

此解决方案使代码更难理解、维护,并且确实难以调试,但一旦经过测试和验证,它就消除了复制粘贴带来的错误可能性。与替代方案相比,结果将是一个更干净、更优雅、更小的代码库。

它实际上将生产代码的开发时间从 3 个月缩短到了几个小时。

关于c - 使用 X 列表和预处理器指令在编译时生成可配置的 C 代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39273219/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com