void * parameters in function pointers

B

Boon

Hello everyone,

AFAIU, void pointers and thing pointers are compatible, in the sense
that it is "legal" to write the following

thing x;
thing *p = &x;
void *q = p;
thing *r = q;

Is my understanding correct?

Consider the following code.

typedef void fun_t(void *);
void dispatch(fun_t fun, void *param)
{
fun(param);
}
void foo(int *p)
{
*p += 1;
}
int main(void)
{
int param = 666;
dispatch(foo, &param); /* WARNING HERE */
return 0;
}

foo.c: In function 'main':
foo.c:13: warning: passing argument 1 of 'dispatch' from incompatible
pointer type

"pointer to function taking void * returning void" and "pointer to
function taking int * returning void" are incompatible?
Even though void * and int * are, themselves, compatible?

The simple fix is to have foo take a void * param, and cast as needed.

typedef void fun_t(void *);
void dispatch(fun_t fun, void *param)
{
fun(param);
}
void foo(void *p) /* CHANGE PARAM TYPE HERE */
{
*(int *)p += 1; /* AND CAST HERE */
}
int main(void)
{
int param = 666;
dispatch(foo, &param);
return 0;
}

Why is the second program valid, while the first elicits a warning?
Is the first program valid or does it invoke UB?
(I don't like the second form much because it requires a cast.)

Regards.
 
H

Hallvard B Furuseth

Boon said:
AFAIU, void pointers and thing pointers are compatible, in the sense
that it is "legal" to write the following

thing x;
thing *p = &x;
void *q = p;
thing *r = q;

Is my understanding correct?

For "thing" = "data", yes. Not for "thing" = "function".
There is no "generic function pointer type" similar to void*,
but you can cast any function types to another and back again.
Just take care to always use a function through it original type.
typedef void fun_t(void *);
void dispatch(fun_t fun, void *param)
{
fun(param);
}
void foo(int *p)
{
*p += 1;
}
int main(void)
{
int param = 666;
dispatch(foo, &param); /* WARNING HERE */
return 0;
}

foo.c: In function 'main':
foo.c:13: warning: passing argument 1 of 'dispatch' from incompatible
pointer type

"pointer to function taking void * returning void" and "pointer to
function taking int * returning void" are incompatible?
Even though void * and int * are, themselves, compatible?

Yes, and yes. With some exceptions, C variables must be accessed
through the same type as with they were created. Your assignment
void *q = p;
above tells the compiler to *convert* p to void*, just as if you
had written a cast. Similarly, when you pass an int* to a fun_t,
the prototype tells the compiler to convert the int* to void*.

When you call a function via a function pointer, it is the prototype in
the pointer which tells the compiler what types to convert the arguments
to. If the function you assigned to the pointer has a different
prototype, your program can break. E.g. on a machine where int* and
void* have different representations, or with a compiler which optimizes
on the assumption that your code has defined behavior (which yours
doesn't).
The simple fix is to have foo take a void * param, and cast as needed.
Yup:

typedef void fun_t(void *);
void dispatch(fun_t fun, void *param)
{
fun(param);
}
void foo(void *p) /* CHANGE PARAM TYPE HERE */
{
*(int *)p += 1; /* AND CAST HERE */

Yup, now each object is accessed via the data type it actually has.
}
int main(void)
{
int param = 666;
dispatch(foo, &param);
return 0;
}

Why is the second program valid, while the first elicits a warning?
Is the first program valid or does it invoke UB?
UB.

(I don't like the second form much because it requires a cast.)

void foo(void *p)
{
int *ip = p;
*ip += 1;
}
 
M

myx

Hello everyone,

AFAIU, void pointers and thing pointers are compatible, in the sense
that it is "legal" to write the following

š šthing x;
š šthing *p = &x;
š švoid *q = p;
š šthing *r = q;

Is my understanding correct?

Consider the following code.

typedef void fun_t(void *);
void dispatch(fun_t fun, void *param)
{
š šfun(param);}

void foo(int *p)
{
š š*p += 1;}

int main(void)
{
š šint param = 666;
š šdispatch(foo, &param); /* WARNING HERE */
š šreturn 0;

}

foo.c: In function 'main':
foo.c:13: warning: passing argument 1 of 'dispatch' from incompatible
pointer type

"pointer to function taking void * returning void" and "pointer to
function taking int * returning void" are incompatible?
Even though void * and int * are, themselves, compatible?

The simple fix is to have foo take a void * param, and cast as needed.

typedef void fun_t(void *);
void dispatch(fun_t fun, void *param)
{
š šfun(param);}

void foo(void *p) /* CHANGE PARAM TYPE HERE */
{
š š*(int *)p += 1; /* AND CAST HERE */}

int main(void)
{
š šint param = 666;
š šdispatch(foo, &param);
š šreturn 0;

}

Why is the second program valid, while the first elicits a warning?
Is the first program valid or does it invoke UB?
(I don't like the second form much because it requires a cast.)

Regards.

Yes, you are right, pointer to void don't require explicit cast to
convert from or to an other type. But pointers to function must be
explicitly casted to pointer to another function. Thus, you should
cast you pointer:
dispatch((void (*)(void *))foo, &param);
In your case I can't use fun_t to cast your function pointer, becouse
you have defined type _function_, but not pointer to function. You
should declare new type like this:
typedef void (*fun_t)(void *);
Now we have type fun_t, that it the pointer to function, taking
pointer to void, and returning void. In your declaration you have type
"function", not pointer to function. And I think you wanted that
dispatch function would take an argument of type "pointer to
function". Your code working because compiler automatically converts
your arg from type "function" to type "pointer to function" (as
function can not be an argument).
So, after we defined fun_t as pointer to function, we can use it in
cast expression
dispatch((fun_t)foo, &param);
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top