2

我不是 C 专家。自从我的 CS1 和大学 2 天以来,我没有做过任何 C。我在这里和那里做了一点 C++,但已经有一段时间了。所以我要问的是解决我正在感知的问题的正确模式。

我决定接受一个相当雄心勃勃的挑战,我正在用 C 来做。我正在(重新)学习的一件事是 C 中的不同抽象技术与我习惯于使用高级语言的抽象技术。我遇到并询问的问题特别与测试和功能有关。

例如,我有两个函数f,如果某些条件为真gf就会调用。g

void f(object* obj) {
  // ...
  if(obj->state)
    g(obj);
  // ...
}

我需要验证它g实际上是被调用的,但我也不想实际执行它,因为它可以做各种各样的其他事情。这通常可以通过接口或抽象类或继承在更高级别的语言中解决。但是在 CI 中没有这些技术。

事实上,我能想到的解决这个问题的唯一方法是利用函数指针。而不是直接调用g,我认为我应该添加一个指向object它的指针,它有一个指向 的指针g,我可以用指向测试中不同函数的指针替换它。

typedef struct object {
  int state;
  void (*g)(object* obj);
} object;

void f(object* obj) {
  // ...
  if(obj->state)
    obj->g(obj);
  // ...
}

然后通常我只是g在分配实例时指向,g但在我的测试中,我将 obj->g 指向不同的函数,该函数仅验证传入的值并注意它实际上被调用了。

这是我现在的想法,但我不确定这是否是解决这个问题的正确 C-ish 方法。希望我的描述能说明我遇到的问题,但我真正想知道的是如何最好地处理它。

在 C 中解决这个问题的推荐设计模式是什么?

4

2 回答 2

1

如果你想改变g在不同调用中调用的函数,也许你应该作为参数f传入:gf

typedef void (*gFunc)(object* obj);

void f(object *obj, gFunc g) {
    ...
    if (obj->state) {
        g(obj);
    }
    ...
}

如果你不想弄乱 的函数签名f,你可以定义一个版本f来调用上面的实现:

void gNormal(object* obj);           //normal implementation of g
void gTest(object* obj);             //test version of g

void fGeneral(object* obj, gFunc g); //general implementation of f as above

void fNormal(object* obj)            
{
    fGeneral(obj, &gNormal);         //use the default version of g
}

从语言的角度来看,无论您选择此方法还是使函数指针g成为对象的成员,都可能大致相同——您需要考虑什么对您的对象结构更有意义。

再说一次,如果你正在做很多这样的事情,也许你应该使用面向对象的语言!

于 2012-08-20T02:33:37.933 回答
0

如果您在编译时知道是否要进入测试用例,则可以有两种不同的 g 实现,它们通过预处理器宏进行控制,例如:

#ifdef TESTING

    int g() { // implement test version here }

#else

    int g() { // implement real version here }

#endif

如果您只在编译时知道,则可以以相同的方式使用全局变量,但在同一函数定义中使用两个实现:

 int g() {
     if (gTesting) {
         // implement test version here
     }
     else {
         // implement real version here
     }
 }
于 2012-08-19T21:59:37.493 回答