HalosGhost
HalosGhost

Reputation: 145

Defining a function as a function pointer

Mostly for fun, I've decided to write my own minimal test framework for my C code. I use a basic struct for the test information, create an array of test structs and then iterate over them to run all the tests. This amounts to a very small amount of work for a fairly elegant (imho) solution.

However, the one thing that is a little annoying is that I cannot figure out how to define functions as function pointers instead of defining the function and then creating a function pointer later.

I have the following (which works just fine):

typedef int (* test_p) (void);

struct test {
    char * desc;
    test_p func;
};

int
example_test (void) {
    puts("This is a test");
    return 0;
}

void
run_test (char * test_name, test_p test) {
    printf("Testing %s\t\t\t[ PEND ]\r", test_name);
    char * test_result = (test() ? "FAIL" : "PASS");
    printf("Testing %s\t\t\t[ %s ]\n", test_name, test_result);
}

int
main (void) {
    struct test test_list [] = {
        { "example test", (test_p )example_test }
    };

    for ( int i = 0; i < 1; i ++ ) {
        run_test(test_list[i].desc, test_list[i].func);
    }

    return 0;
}

However, I am hoping I can remove the need for the casting in the struct and instead define the function as being a function pointer from the beginning. The following is an example of how I would like this to work (assuming many of the same things as above):

test_p
example_test = {
    puts("This is a test");
    return 0;
}

If I could do something like this, then in the struct, I could simply have the func field be example_test rather than (test_p )example_test. Is this (or something like it) possible? If not, is there a reason why not (If that reason is simply "because it wasn't added to the language", that's fine)?

Upvotes: 3

Views: 261

Answers (2)

Jim Balter
Jim Balter

Reputation: 16406

A function pointer is one kind of thing and a function is another kind of thing so you can't really make the latter be the former. But if you use a function name where a function pointer is expected, that produces a pointer to the function, so you can just remove the unnecessary cast, as WhozCraig said in the first comment above. You write

If I could do something like this, then in the struct, I could simply have the func field be example_test rather than (test_p )example_test.

You can do that, with example_test defined just as it is in your current code ... did you try that?

You can also forward declare a function, like so:

typedef int test_func(void); // note no indirection
typedef test_func* test_p;

test_func example_test;

It would be nice if you could use that sort of syntax when you define the function, as in your attempted syntax, but there's simply no way to do that in C ... you have to explicitly provide the return type and parameter list.

Another detail is that, when you invoke the function pointed to by a function pointer, you don't have to dereference it ... that's why you were able to write

test()

instead of

(*test)()

although the latter also works. (In fact, because the deference is stripped, (********test)() also works ... but only do that if you're trying to win an obfuscation contest.)

Upvotes: 3

david.pfx
david.pfx

Reputation: 10868

What you are describing is a kind of meta-programming. Rather than writing code to explicitly solve the problem, you are concerned with a kind of syntactic structure that will allow you to define a whole raft of test functions without unnecessary cruft.

In Lisp you would use macros. In C++ you might use templates and/or lambdas. In C you use macros.

So you need to write a macro that:

  • takes a name and descriptive text as arguments
  • defines a static variable of type function (created from that name using token pasting)
  • defines a function (using a name created by token pasting)

[edit] At this point you have achieved the goal: you have created the function and given it a name that is (only) a function pointer, and you can use that name in your struct without a cast. I would suggest one additional step, the macro also:

  • adds the variable/function and descriptive text to a list of functions to be tested.

Then your boilerplate loop iterates over the structure calling each function and reporting the results using the descriptive text. Problem solved.

Some people don't like macros, but they are ideally suited to this situation, and there is no other way to do it in C. I did something just like this before making the move to C++.

Upvotes: 1

Related Questions