Re: [SLUG] [PIG] call a function without knowing its name in C

From: Dylan William Hardison (dylan@hardison.net)
Date: Sun May 28 2006 - 10:54:13 EDT


Spake Jonathon Conte on Sunday, May 28, 2006 at 01:39AM -0400:
> I'm writing a little project in C and have hit a wall. Let's say I have
> Functions A, B, C, & D. How can I make A dynamically call B, C or D based
> on a keyword in a text file *without* A knowing the exact names of
> functions B, C or D beforehand?
>
> Is there some trick I can do with #define, enum and function pointers? Or
> perhaps some other way to go about it? The goal is to make it easy to add
> new functions to the program without having to continually modify all the
> functions that might call them.
>
> Perhaps I am overly complicating things with abstraction but I am still
> curious to see if it can be done.
>

If you need this level of expressivity, C is not the ideal language.
The best you can get in C would be a hashtable of function pointers, and
this is not very pretty. Nevertheless...

A hashtable of function pointers will work.
I would recommend using the "glib" (Note: Note glibc).
http://developer.gnome.org/doc/API/2.0/glib/index.html

Specifically, we can use its GHashTable data structure and functions.
http://developer.gnome.org/doc/API/2.0/glib/glib-Hash-Tables.html

Here's an example program that you should be able to modify to your
liking:

--- funhash.c ---
#include <stdio.h>
#include <glib.h>

/* compile with something like:
 * gcc -o funhash `pkg-config glib-2.0 --libs --cflags` funhash.c
 */

/*
 * gboolean is the same as bool, except it exists on all platforms glib support.
 * gpointer is the same as void *
 */

typedef gboolean (*Callback)(gpointer);

void defun(GHashTable *hash, char *name, Callback callback)
{
        g_assert(hash != NULL);
        g_assert(name != NULL);
        g_assert(callback != NULL);
        g_hash_table_insert(hash, (gpointer) name, (gpointer) callback);
}

gboolean apply(GHashTable *hash, char *name, char *arg)
{
        Callback callback;
        g_assert(hash != NULL);
        g_assert(name != NULL);

        callback = (Callback) g_hash_table_lookup(hash, (gpointer) name);
        
        return callback(arg);
}

gboolean fun_a(char *msg)
{
        printf("A: %s\n", msg);
}

gboolean fun_b(char *msg)
{
        printf("B: %s\n", msg);
}

gboolean fun_c(char *msg)
{
        printf("C: %s\n", msg);
}

int main(char *argv, int argc)
{
        GHashTable *funs = g_hash_table_new(g_str_hash, g_str_equal);
        
        defun(funs, "A", (Callback) fun_a);
        defun(funs, "B", (Callback) fun_b);
        defun(funs, "C", (Callback) fun_c);
        
        apply(funs, "C", "foo");
        apply(funs, "B", "bar");
        apply(funs, "A", "baz");

        return 0;
}
/* EOF */

-- 
Entropy requires no maintenance.
              -- Markoff Chaney
-
GPG Fingerprint: E3CD FDAB 82C4 14FD 7B57  430B 770E 0EAF FB53 12C2
-----------------------------------------------------------------------
This list is provided as an unmoderated internet service by Networked
Knowledge Systems (NKS).  Views and opinions expressed in messages
posted are those of the author and do not necessarily reflect the
official policy or position of NKS or any of its employees.



This archive was generated by hypermail 2.1.3 : Fri Aug 01 2014 - 19:27:17 EDT