我正在 C 中实现一个非常非常的基本组件系统,但现在我想要“动态”调用某些函数。设置非常简单:主程序只是一个无限循环,其中检查一些条件,并为每个启用的组件调用“进程”函数。
例如,现在它的工作原理如下:
while (1) {
input_process();
network_process();
graphics_process();
}
但是我想将它分成单独的组件,并以某种方式在中心位置定义使用哪些部件。这可以通过简单的定义来完成,如下所示:
#define HAS_NETWORK
...
while (1) {
input_process();
#ifdef HAS_NETWORK
network_process();
#endif
graphics_process();
}
正如你所看到的那样,对于1或者只有少数几个组件,这是好的,但是如果我想在未来对所有这些(输入,网络和图形)和其他组件这样做,我将不得不分开每个人都有#ifdefs,这很乏味。
在伪代码中,我想要完成的是以下内容:
components = {'input', 'network', 'graphics'}
...
foreach component in components
execute component_process()
这样可以在将来轻松添加组件。 我不介意检查是在编译时还是在运行时完成(虽然我显然更喜欢编译时,但我可以想象运行时更容易实现)。我不知道怎么开始。
答案 0 :(得分:11)
你需要指向函数的指针,创建一个指向函数的指针数组并动态索引它。
这里有关于函数指针的link。
答案 1 :(得分:5)
编译时解决方案:在该循环内部进行预构建步骤和include指令,例如
while (1) {
#include "components.generated.c"
}
生成该文件的基本脚本可能看起来像(Python):
components = ('input', 'networking', 'graphics')
# this could also be e.g. a glob on a directory or a config file
with open('components.generated.c', 'w') as fp:
for component in components:
print >>fp, '%s_process();' % component
任何体面的构建系统都可以让你这样做。
答案 2 :(得分:3)
功能指针很棒!
typedef void (*process_fun)(void);
process_fun processes[] =
{ input_process, network_process, graphics_process };
#define NELEMS(A) (sizeof(A) / sizeof((A)[0]))
while (1) {
for (int i = 0; i < NELEMS(processes); i++)
processes[i]();
}
我从Dave Hanson那里学到的NELEMS
宏也是我的最爱之一。
P.S。不惜一切代价避免使用#ifdef
: - )
答案 3 :(得分:2)
ol'if condition有什么问题?
if (hasNetwork)
{
network_process();
}
答案 4 :(得分:1)
你可以用一系列函数指针来做到这一点。一般来说,我试着避免像瘟疫一样的函数指针,但它可能是你最好的选择。
或者,你可以创建一个带有int参数的组件处理函数,然后有一个令人讨厌的switch语句......但是要使它工作,你需要继续添加到component_process函数。
或者 - 或者,您可以在C ++中执行此操作,创建一个虚拟Component类,它只有一个方法“process”,带有一堆子类,并且您运行一组组件(实际上是子类的对象)并调用流程方法。
答案 5 :(得分:1)
你的组件应该是一个指向函数的指针数组
enum components
{
input,
network,
graphics,
num_components
}
void process_audio()
{
}
void process_network()
{
}
void process_graphics()
{
}
void (*process_component[num_components])();
process_component[0] = &process_audio;
process_component[1] = &process_network
process_component[2] = &process_graphics;
for (int i = 0; i < num_components; i++)
process_component[i]();
答案 6 :(得分:1)
在编译时使用X宏:
component.x是一个包含以下内容的文件:
COMPONENT( graphic , "3D graphics rendering" )
COMPONENT( network , "Network" )
COMPONENT( other , "usefull stuff" )
#undef COMPONENT
将其用于:
#define COMPONENT( what , description ) what ## _process();
while (1)
{
#include "components.x"
}
例如在另一个地方:
std::cout << "We use :\n" ;
#define COMPONENT( what , description )\
std::cout << #what << " : " << description << "\n" ;
#include "components.x"
并且可以将HAS_定义放在component.x中的单个位置:
#ifdef HAS_GRAPHIC
COMPONENT( graphic , "3D graphics rendering" )
#endif
#ifdef HAS_NETWORK
COMPONENT( network , "Network" )
#endif
#ifdef HAS_OTHER
COMPONENT( other , "usefull stuff" )
#endif
#undef COMPONENT
答案 7 :(得分:0)
以下是在运行时使用函数指针数组执行此操作的语法示例:
void f( void ) { puts( "f" ); } void g( void ) { puts( "g" ); } void h( void ) { puts( "h" ); } void (*array[])(void) = { f, h, 0 }; int main(void) { void (**t)(void); for( t = array; *t; t++ ) (*t)(); }
答案 8 :(得分:0)
另一种可能性:按原样保持循环,即
while (1) {
input_process();
network_process();
graphics_process();
}
并将以下预处理程序指令添加到文件头:
#ifndef HAS_NETWORK
#define network_process() ((void)0)
#endif
#ifndef HAS_GRAPHICS
#define graphics_process() ((void)0)
#endif