如何有条件地确定在编译时调用哪些函数?

时间:2009-12-03 15:50:16

标签: c function dynamic c-preprocessor

我正在 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()

这样可以在将来轻松添加组件。 我不介意检查是在编译时还是在运行时完成(虽然我显然更喜欢编译时,但我可以想象运行时更容易实现)。我不知道怎么开始。

9 个答案:

答案 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