justin.m.chase
justin.m.chase

Reputation: 13675

Instance Level Abstractions in C

I am not a C expert. I haven't done any C since my CS1 & 2 days in college. I have done a little C++ here and there but it's been a while. So what I'm asking about is the correct pattern to solve a problem I am perceiving.

I have decided to take on a fairly ambitious challenge and I am doing it in C. One of the things I am (re)learning is the different abstraction techniques in C vs. the ones I am used to having in higher level languages. The problem I am encountering, and asking about, specifically has to do with testing and functions.

For example, I have two functions f and g and f will call g if certain conditions are true.

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

I need to verify that g is actually being called but I also don't want to actually execute it, since it can do all sorts of other things. This would normally be solved in a higher level language by means of interfaces or abstract classes or inheritance. But in C I don't have these techniques.

In fact the only solution to this problem that I can think of is to utilize function pointers. Instead of calling g directly I think I should add a pointer to object such that it has a pointer to g, which I can replace with a pointer to a different function in tests.

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

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

Then normally I just point to g when allocating an instance of g but in my test I point obj->g to a different function, one that merely verifies the incoming values and notes that it was actually called.

This is the idea I am having right now but I'm not sure if it's quite the correct C-ish way to solve this problem. Hopefully my description illustrates the problem I am encountering but what I am really wondering is how best to handle it.

What are the recommended design patterns for solving this problem in C?

Upvotes: 2

Views: 120

Answers (2)

Brian L
Brian L

Reputation: 3251

If you want to change the function g called in different calls of f, maybe you should pass in g as a parameter to f:

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

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

If you didn't want to mess up the function signature of f, you can define a version of f to call the above implementation:

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
}

Whether you choose this method or to make the function pointer g a member of the object is probably about the same from the language's point of view - you need to consider what makes more sense for your object structure.

Then again, if you are doing lots of stuff like this, maybe you should be using an object-oriented language!

Upvotes: 1

David
David

Reputation: 1419

If you know at compile time whether you want to be in the testing case, you can have two different implementations of g that are controlled via preprocessor macros, so something like:

#ifdef TESTING

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

#else

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

#endif

If you only know at compile time, you could give use a global variable in the same way, but with both implementations in the same function definition:

 int g() {
     if (gTesting) {
         // implement test version here
     }
     else {
         // implement real version here
     }
 }

Upvotes: 0

Related Questions