callback function pointer with argument in C language - c

I have the following working code in C language, func1 and func2:
void func1(int (*callbackf)(void *, void *)){
void a = NULL;
void b=NULL;
//do some work and then call comp
callbackf (a,b)
}
void func2(int (*callbackf)(void *), void *a, void *b){
// do some work, not necessary works on a and b.
callbackf(a,b);
}
I am writing here to ask you if it is possible to do something like this (func3)
void func3(int (*callbackf)(void *), void *a, void *b){
// do some work, not necessary works on a and b.
callbackf(a,b);
}
is it possible? does it make sense?
regards
Alex

Related

Generic Quicksort

Below are the code snippets of generic qsort on C.
What do I write in the fourth parameter of the genmyqsort when it's called in the recursion?
int compnode(node *a, node *b){
return(strcmp(a->name,b->name));
}
void genmyqsort(void *a, int n, int size, int (*fcmp)(const void*,const void*)){
int pivot;
if(n>1){
pivot=partition(a,n,size);
genmyqsort(a*size, pivot,size);
genmyqsort(a+(pivot+1)*size,n-pivot-1,size);
}
}
call of Qsort in main.
genmyqsort(b,n,sizeof(node),(int(*)(const void*, const void*)) compnode);
You pass the same comparator as you got from the caller (fcmp):
genmyqsort(a*size, pivot, size, fcmp);
genmyqsort(a+(pivot+1)*size, n-pivot-1, size, fcmp);
This will ensure that all instances of genmyqsort() in the call tree will compare array elements in exactly the same way.

Void-pointers in generic stack implementation (Plain C)

I'm trying to make a generic stack in plain C and I have some problems with pointers and no idea where is the problem.
Here's the structure and functions, where I have problems:
typedef struct{
void *elems;
int elemSize;
int logLength;
int allocLength;
} genStack;
void GenStackPush(genStack *s, const void *elemAddr);
void GenStackPop(genStack *s, void *elemAddr);
That's the implementation:
void GenStackPush(genStack *s, const void *elemAddr)
{
s->elems[s->logLength] = elemAddr;
s->logLength++;
}
void GenStackPop(genStack *s, void *elemAddr)
{
s->logLength--;
elemAddr = s->elems[s->logLength];
}
The usage should look like this:
int val;
genStack IntegerStack;
for (val = 0; val < 6; val++)
GenStackPush(&IntegerStack, &val);
GenStackPop(&IntegerStack, &val);
printf("Popped: %d\n",val);
And here are the problems I get:
genstacklib.c: In function ‘GenStackPush’:
genstacklib.c:60:10: warning: dereferencing ‘void *’ pointer [enabled by default]
genstacklib.c:60:2: error: invalid use of void expression
genstacklib.c: In function ‘GenStackPop’:
genstacklib.c:72:23: warning: dereferencing ‘void *’ pointer [enabled by default]
genstacklib.c:72:13: error: void value not ignored as it ought to be
I have tried already several ways to fix the code, but none of them worked.
Thanks.
==========================================================================
So, guys, thanks for help! Now it compiles, but I have changed an API, which was given by our Professor. There was also the problem with 'const' qualifier, so I deleted them. Not my code looks like this:
genstacklib.h:
#ifndef GENSTACKLIB_H
#define GENSTACKLIB_H
#define GenStackInitialAlocationSize 4
typedef struct{
void** elems;
int elemSize;
int logLength;
int allocLength;
}genStack;
void GenStackNew(genStack *s,int elemSize);
void GenStackDispose(genStack *s);
int GenStackEmpty(const genStack *s);
void GenStackPush(genStack *s, void *elemAddr);
void GenStackPop(genStack *s, void *elemAddr);
#endif
genstacklib.c:
#include <stdlib.h>
#include <stdio.h>
#include "genstacklib.h"
void GenStackNew(genStack *s,int elemSize)
{
void** newElems;
/* Allocate a new array to hold the contents. */
newElems = (void**) malloc(elemSize * GenStackInitialAlocationSize);
if (newElems == NULL)
{
fprintf(stderr, "Error with allocating the stack.\n");
exit(1); /* Exit, returning error code. */
}
s->elems = newElems;
s->allocLength = GenStackInitialAlocationSize;
s->logLength = 0; /*is empty*/
}
void GenStackDispose(genStack *s)
{
s->allocLength = 0;
free(s->elems);
}
int GenStackEmpty(const genStack *s)
{
return s->logLength == 0;
}
void GenStackPush(genStack *s, void *elemAddr)
{
s->elems[s->logLength] = elemAddr;
s->logLength++;
}
void GenStackPop(genStack *s, void *elemAddr)
{
s->logLength--;
elemAddr = s->elems[s->logLength];
}
If you have any ideas to improve it or something to say about it, I would hear with pleasure. :D
you are trying to dereference void pointer without typecasting to some other type which causing the problem.
elems has the wrong type. If you declare it as void* the compiler does not know how big the things it points to are. So it can't do pointer arithmetic or array subscripting on it or even dereference what it points to.
Conceptually elems is an array of the things that you put on the stack. What do you put on the stack? Pointers - declared as void*. So elems should be an array of void* objects. You can declare it like this
typedef struct{
void *elems[STACK_SIZE];
int elemSize;
int logLength;
int allocLength;
} genStack;
which will reserve space in the struct for the array (making the struct itself very big), or you can declare it as a pointer to void* i.e. void**
typedef struct{
void **elems;
int elemSize;
int logLength;
int allocLength;
} genStack;
If you go for this option, you then have to manually allocate the memory
genStack* genStackAlloc()
{
genStack* ret = calloc(1, sizeof *ret);
ret->elemns = calloc(STACK_SIZE, sizeof(void*));
// rest of the initialisation
return ret;
}
And of course, you'll have to manually free the memory when you dispose of the stack.
elems is declared as a pointer to a void, where I think you want it to be a pointer to a void*.
The problem is s->elems[s->logLength] :
First, the member variable void *elems use to store the element address (void *), array of the element (void ), so the type of the elems should be (void *), and you should allocate the memory to store the address.
You can allocate memory by the following ways:
void * elems[MAX_STACK_SIZE];
OR
void ** elems
s->elems = (void**)malloc(MAX_STACK_SIZE*sizeof(void*)); // and allocate it before use it.

is this a void pointer? casting? what is it doing?

I am new to the C language and pointers and I am confused by this function declaration:
void someFunction(int (*)(const void *, const void *));
Can anyone explain in layman's terms what this does and how it works?
It's the prototype of a function that takes:
a pointer to a function that takes a const void* and a const void* as arguments and returns an int
as an argument, and returns void.
It declares a function, which takes another function as its argument, and returns nothing. The other function would be declared as
int otherfunction( const void *, const void * );
and you would call somefunction() like this:
somefunction( otherfunction );
It's a function that has a single parameter. That parameter is a pointer to a function that returns an int and takes those two void pointers to constant data parameters.
This is the declaration of a function which takes a function pointer as its argument. In its most basic form, it looks like this:
void someFunction(argument_type);
Where argument_type is int (*)(const void *, const void *), which can be described as a "pointer to a function that takes two const void * arguments, and returns an int". i.e. any function that has the following declaration:
int foo(const void *, const void *);
To illustrate by example:
int foo_one(const void * x, const void * y) { ... }
int foo_two(const void * x, const void * y) { ... }
void someFunction(int (*)(const void *, const void *) function_ptr)
{
const void * x = NULL;
const void * y = NULL;
int result;
result = (*function_ptr)(x, y); // calls the function that was passed in
}
int main()
{
someFunction(foo_one);
someFunction(foo_two);
return 0;
}
Check this very helpful when dealing with complex declarations.

passing a function as a parameter

void dispatch_for(dispatch_queue_t *queue, long number, void (* work)(long)){
int loop = number;
int i;
task_t *ctask;
for(i = 0; i<loop;i++){
ctask = create_task((void *)work,number,"for_test");
dispatch_async(queue,ctask);
}
}
task_t *task_create(void (* work)(void *), void *param, char* name){
//do something
}
I'm getting work as a function and need to pass it to the function create_task..(1st parameter)
How should i pass it?
name of the function without the parentheses is the pointer to that function :
void work(void) {
...;
}
void main(void) {
task_create(work, void, void);
}
Just use the identifier like any other parameter:
dispatch_for(queue, number, work);
The easiest thing would be a typedef to the wanted function type. So you can do
typedef void workfunc_t(void *);
workfunc_t sample_workfunc; // in order to ensure type-correctness
void workfunc_t(void *)
{
// ...
}
void dispatch_for(dispatch_queue_t *queue, long number, workfunc_t * work)
{
int loop = number;
int i;
task_t *ctask;
for(i = 0; i<loop;i++) {
ctask = create_task(work, number, "for_test");
dispatch_async(queue,ctask);
}
}
task_t *task_create(workfunc_t work, void *param, char* name){
//do something
}
The function work doesn't have the same signature in dispatch_for and task_create (the argument is a pointer in one, a long in the other)
It seems strange you want to use the same function in both cases
Since you're using C, and work is a type void (*)(long), but you want to make it a void (*)(void*), simply re-cast the type of work (this is can be done the easiest by using a typedef)
//declare somewhere at a global level
typedef void (*task_create_func)(void*);
//at the point where you want to call task_create
task_create((task_create_func)work, PARAM1, PARM2);
Alternatively, if you don't want to deal with typedefs, you can simply do the cast using the desired pointer-type at the point-of-call like so:
task_create((void (*)(void*))work, PARAM1, PARAM2);

Accessing members of the struct via void *

The solution consists of two parts, one is a static library that receives instances of struct from the user of the library. Library doesn't know what will be the type of structs, all it knows there will be two function pointers to it with a specific name.
Library Code
pre-compiled library has no way of knowing types of user structs, hence receiving via void*
void save(void *data) {
// library will save/cache user's object
data->registered(); // if register successful
}
void remove(void *data) {
// library will remove the object from memory
data->remove(); // if removed successful
}
User of the Library Code
struct Temp { // random order of fields
void (*custom1)();
void (*registered)();
void (*custom2)();
void (*remove)();
void (*custom3)();
}
void reg() {
printf("registered");
}
void rem() {
printf("removed");
}
void custom1() {}
void custom2() {}
void custom3() {}
var temp = malloc(struct Temp, sizeof(struct Temp));
temp->registered = reg;
temp->remove = rem;
temp->custom1 = custom1; // some custom functions
temp->custom2 = custom2;
temp->custom3 = custom3;
// calling library code
save(temp);
remove(temp);
Q. Is there a way for the Library to know how to iterate and go through member fields and see if there's a pointer to such function and call it available.
Is there a way for the Library to know how to iterate and go through member fields and see if there's a pointer to such function and call it available.
No there is not.
Your best bet is to create a structure in the library that has these members, and pass that structure instead of void*.
As #immibis said, there is no way for this to work (i.e. no way for the compiler to justify compiling such code) if the compiler does not know what the types of the data being passed to the function are.
Since you wanted to pass the objects along to the library without storing information about the type of each object in the library, you can fake polymorphism in C, by doing the following:
callback.h
#ifndef _CALLBACK_H_
#define _CALLBACK_H_
typedef struct {
void (*registered)();
void (*removed)();
} ICallback;
#endif _CALLBACK_H_
pre_comp.h
#ifndef _PRE_COMP_H_
#define _PRE_COMP_H_
#include "callback.h"
void save(ICallback* data);
void remove(ICallback* data);
#endif /* _PRE_COMP_H_ */
precomp.c
#include <stdlib.h> /* NULL */
#include "callback.h"
#include "pre_comp.h"
void save(ICallback *data) {
if (NULL != data && NULL != data->registered) {
data->registered(); // if register successful
}
}
void remove(ICallback *data) {
if (NULL != data && NULL != data->removed) {
data->removed(); // if removed successful
}
}
main.c
#include <stdio.h>
#include "pre_comp.h"
#include "callback.h"
struct Temp {
ICallback base; // has to be defined first for this to work
void (*custom1)();
void (*custom2)();
void (*custom3)();
};
// calling library code
void reg() {
puts("registered");
}
void rem() {
puts("removed");
}
int main() {
struct Temp data = {{reg, rem}};
save((ICallback*)&data);
remove((ICallback*)&data);
}
compiling
gcc pre_comp.c main.c
output
registered
removed
If the library has 0 information about the possible struct types, then you
cannot do it. The library has to get somehow the information or the offsets.
The only way I can think of is:
All register member have the same prototype
Pass the offset to the function.
I created an example of this
#include <stdio.h>
#include <stddef.h>
#include <stdint.h>
// function that does not know anything about any struct
void reg(void *data, size_t offset)
{
uintptr_t *p = (uintptr_t*) (((char*) data) + offset);
void (*reg)() = (void(*)()) *p;
reg();
}
struct A {
int c;
void (*reg)();
};
struct B {
int b;
int c;
void (*reg)();
};
void reg_a()
{
printf("reg of A\n");
}
void reg_b()
{
printf("reg of B\n");
}
int main(void)
{
struct A a;
struct B b;
a.reg = reg_a;
b.reg = reg_b;
reg(&a, offsetof(struct A, reg));
reg(&b, offsetof(struct B, reg));
return 0;
}
This prints:
$ ./c
reg of A
reg of B
I run it with valgrind and I did not get any errors nor warnings. I'm not sure if
this violates somehow strict aliasing rules or yields undefined behaviour
because of the uintptr_t* conversions, but at least it seems to work.
I think however, the more cleaner solution is to rewrite the register (btw. register
is a keyword in C, you cannot use that for a function name) function to
accept a function pointer and possible parameters, something like this:
#include <stdio.h>
#include <stdarg.h>
void reg(void (*func)(va_list), int dummy, ...)
{
if(func == NULL)
return;
va_list ap;
va_start(ap, dummy);
func(ap);
va_end(ap);
}
void reg1(int a, int b)
{
printf("reg1, a=%d, b=%d\n", a, b);
}
void vreg1(va_list ap)
{
int a = va_arg(ap, int);
int b = va_arg(ap, int);
reg1(a, b);
}
void reg2(const char *text)
{
printf("reg2, %s\n", text);
}
void vreg2(va_list ap)
{
const char *text = va_arg(ap, const char*);
reg2(text);
}
int main(void)
{
reg(vreg1, 0, 3, 4);
reg(vreg2, 0, "Hello world");
return 0;
}
This has the output:
reg1, a=3, b=4
reg2, Hello world
Note that reg has a dummy parameter. I do that because the man page of
stdarg says:
man stdarg
va_start():
[...]
Because the address of this argument may be used in the va_start() macro,
it should not be declared as a register variable, or as a
function or an array type.
You can take an approach similar to qsort and pass function pointers in addition to a void pointer to the structure.
Here is the function prototype for qsort, which is a function that can be used to sort arrays of any type:
void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *));
It takes a function pointer that performs the comparison because without it qsort wouldn't know how to compare two objects.
This can be applied to your task with a function prototype like this:
int DoFoo(void *thing, void (*register)(void *), void (*remove)(void *))
This function takes a void pointer to your struct and then two functions that it can call when it needs to register or remove that struct. Having the functions be members of the struct is not required and I generally do not recommend it. I recommend reading up on qsort because it is does something similar to what you are trying to do.

Resources