简体   繁体   中英

C: typecasting function pointers from generic input arg (void*) into specific (char*/int *) arg and/or different return types, void, int

I have specific data types:

typedef struct _A_s { ... } A_t;
typedef struct _B_s { ... } B_t;

I also have specific functions to operate on these (eg A_t * init_A(); free_A(A_t *); print(A_t *); etc.

A 3rd function takes in any of those data struct types via a void * and also function pointers in order to free and print its input. I want to keep this function generic, hence converting A_t* to void* . But I am not sure how that will work with function pointers.

Here is a rough (sorry:) sketch:

typedef (void )(*free_generic_t)(void *);
typedef (void )(*print_generic_t)(void *);
void myfunc(
  void *object,
  free_generic_t free_fn,
  print_generic_t print_fn
){
  ...
  print_fn(object);
  free_fn(object);
}

My aim is to do this:

A_t *a = init_A(...);
B_t *b = init_B(...);
myfunc((void *)a, free_A, print_A);
myfunc((void *)b, free_B, print_B);

but gcc complains because of -Werror=incompatible-pointer-types , which I want to keep on. Ignoring this warning, the program works fine.

When I did this typecastI got a SIGSEGV it worked fine and passed the valgrind test:

myfunc(
  (void *)a,
  (free_generic_t )free_A,
  (free_generic_t )print_A
);

Question 1: How far can I go in typecasting functions to function pointers in the above scenario? Assume that the number of input parameters is fixed. That is, all print_A() 's take just 1 argument in, which will be a pointer.

Question 2: The problem becomes more complex when some of those specific functions return int and some nothing ( void ). Can I adjust the generic function pointers to return int in order to accommodate both flavours of specific functions even if some of them return void ?

Update : I don't get a SIGSEGV when I typecast the function pointers, it was a mistake of mine. I have edited my post in place.

Give those structs

typedef struct _A_s { ... } A_t;
typedef struct _B_s { ... } B_t;

an pointer to a deallocator function and populate it in the A_t * init_A(); respectively B_t * init_B(); .

Then you may write a generic deallocator for both of them which indirectly calls the deallocator via the stored pointer.

// Anything, which is shared between structures
typedef struct _X_s { void (*deallocator)(void *); ... } X_t;

typedef struct _A_s { X_t x; ... } A_t;
typedef struct _B_s { X_t x; ... } B_t;

Then

void deallocate(X_t *x){
    x -> deallocator(x);
}

int main(void){
    A_t *a = init_A();
    B_t *b = init_B();

    deallocate((X_t *)a);
    deallocate((X_t *)b);
}

Please be aware that this is only a concept of how you can do it. You must work out the details by yourself and add validity checks and such.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM