Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to insert function address into hashtable?

I want to save some functions into hashtable, the key is integer(some id), the value is function(or address?). My question is, how to store them in hashtable, so I can get a function by key? The hashtable insert function is like:

int ht_insert(ht_table *ht, void *key, size_t key_len, void *value, size_t value_len)

int func(void *){...}

My code is:

ht_insert(ht_tab, &myid, sizeof(myid), &func, sizeof(func));

and it doesn't work well.

-----------------------More details below----------------

1.The hashtable can be set to COPY or REFERENCE mode, I choose COPY mode(both key and value). 2.In fact I use function pointer as parameter, my original post may confused somebody. So I put some more codes here:

typedef int (*request_callback)(void *request); //typedef a function pointer

int add_callback_by_id(int id, request_callback cb)
{
...
    ht_insert(ht_tab, &id, sizeof(id), cb, sizeof(request_callback));
...
}

//here, pointer of func is passed to add_callback_by_id
add_callback_by_id(request_id, &func);

//
if ((cb = ht_lookup(ht_tab, &id, sizeof(id))) != null)
{
....
    (*(request_callback)cb)(request); //crashed here!
....
}

Finally, I use user694733's solution, by define a wrapper structure. It works!

typedef struct _callback_obj
{
    request_callback cb;
}callback_obj;

int add_callback_by_id(int id, request_callback cb)
{
    callback_obj cb_obj;
...
    cb_obj.cb = cb;
    ht_insert(ht_tab, &id, sizeof(id), &cb_obj, sizeof(callback_obj));
...
}

//
if ((pcb_obj = ht_lookup(ht_tab, &id, sizeof(id))) != null)
{
....
    (*(request_callback)pcb->cb)(request); //works, ^-^!
....
}

Although it works, but not convenience.

like image 548
geniuslinchao Avatar asked Apr 12 '26 14:04

geniuslinchao


1 Answers

It would appear your hash table stores both the key and value by address (and requires a size therein for each). You're already storing your id by address. This is one way you can store your function pointer by address as well:

int (*myfunc)(void*) = &foo;

ht_insert(ht_tab, &myid, sizeof(myid), &myfunc, sizeof(myfunc));

Explanation

Storing a proc address as written in to this hash table is not going to do what you think it will. , Its a code address. Specifying a sizeof() (which shouldn't even work) will simply tell the hash table to goto that code address and copy out the specified size in bytes, storing that as the value. If the actual passed pointer were the pointer being stored, it would work, but then the size-parameter would also be useless. I'm quite-convinced this is a copy-by-address hash table, and as such, the value you need to pass is the address of a function pointer; not a simple function address. Without the exact function prototype for your value retrieval function I cannot show you how to get the function pointer back out and use it.

Note: I'm quite-sure the hash table doesn't care if your local variables like myid and myfunc go out of scope, and will happily invoke UB (at least on the key) trying to use data that is no longer valid. So i would suggest you either make them dynamic or otherwise ensure the data for keys and values you provide lives at least as long as your hash table.


Update (after OP addendum.1 to question)

Per code from the OP:

typedef int (*request_callback)(void *request); //typedef a function pointer

int add_callback_by_id(int id, request_callback cb)
{
...
    // This is wrong, but very close to correct
    ht_insert(ht_tab, &id, sizeof(id), cb, sizeof(request_callback));
...
}

The above should look like this:

int add_callback_by_id(int id, request_callback cb)
{
...
    // Pay note to the & operator. The change in sizeof() param is advisable
    ht_insert(ht_tab, &id, sizeof(id), &cb, sizeof(cb));
...
}

The retrieval and usage should look like this:

request_callback* ppfn = NULL; // note pointer-to-pointer-to-function

if ((ppfn = ht_lookup(ht_tab, &id, sizeof(id))) != null)
{
    (*ppfn)(request);
}

Example

The following rather trivial program demonstrates the above technique. Because I have no access to the OP's hash-table implementation, I'm afraid this is about as simple as I can make it:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

// these are normally in the hash table.
void *data;
size_t len;

typedef void (*callback_proc)(void*);

void set_callback(callback_proc cb)
{
    data = malloc(sizeof(cb));
    memcpy(data, &cb, sizeof(cb));
}

void *get_callback()
{
    return data;
}

// simple implementation. does nothing
void my_callback(void* pv)
{
    printf("My_callback called!\n");
}

int main(int argc, char *argv[])
{
    // invoke our inserter function
    set_callback(my_callback);

    // retrieval. note the pointer-to-pointer-to-function
    callback_proc* ppfn = get_callback();
    (*ppfn)(NULL);

    return 0;
}

Output

My_callback called!
like image 52
WhozCraig Avatar answered Apr 15 '26 09:04

WhozCraig