Why Are Function Pointers and Data Pointers Incompatible in C/C++

Why are function pointers and data pointers incompatible in C/C++?

An architecture doesn't have to store code and data in the same memory. With a Harvard architecture, code and data are stored in completely different memory. Most architectures are Von Neumann architectures with code and data in the same memory but C doesn't limit itself to only certain types of architectures if at all possible.

function pointer and function is incompatible because of arguments

You have to respect pointer definition: pointer need that first parameter is a pointer to void, so your function implementation should have first parameter as void:

void ShapeSetX(void *void_shape, int x){
Shape *shape = (Shape*) void_shape;
shape->x = x;
}
void ShapeSetY(void *void_shape, int y){
Shape *shape = (Shape*) void_shape;
shape->y = y;
}
int ShapeGetX(void *void_shape){
Shape *shape = (Shape*) void_shape;
return shape->x;
}
int ShapeGetY(void *void_shape){
Shape *shape = (Shape*) void_shape;
return shape->y;
}

Incompatible pointer type when making structure of function pointers

You have a mismatch in levels of pointers:

typedef int (*pointer_func)(Game *); << Pointer type

typedef struct
{
char *funcName;
pointer_func *f; << Pointer to a pointer type.... OOPS
}userFunc;

Make *f -> f and it should work.

Function pointers in C: warning: assignment from incompatible pointer type [-Wincompatible-pointer-types]

The type of the second argument differs between the functions, and the function-pointer variable.

In the functions it's a pointer to const, which it isn't in the function-pointer variable.

The type needs to be exactly equal.

Is casting a function pointer that takes a const pointer argument to the equivalent function but with non constant pointer arguments OK?

This is not allowed because the types of one of the corresponding parameters is not compatible.

Compatible types are defined in section 6.2.7p1 of the C standard:

Two types have compatible type if their types are the same. Additional
rules for determining whether two types are compatible are described
in 6.7.2 for type specifiers, in 6.7.3 for type qualifiers, and in
6.7.6 for declarators. ...

And section 6.7.3p10 details compatibility of qualified types:

For two qualified types to be compatible, both shall have the
identically qualified version of a compatible type; the order of type
qualifiers within a list of specifiers or qualifiers does not affect
the specified type.

This means that const void * and void * are not compatible.

Compatibility of function types is described in section 6.7.6.3p15:

For two function types to be compatible, both shall specify compatible
return types. Moreover, the parameter type lists, if both are
present, shall agree in the number of parameters and in use of the
ellipsis terminator; corresponding parameters shall have compatible
types.
If one type has a parameter type list and the other type is
specified by a function declarator that is not part of a function
definition and that contains an empty identifier list, the parameter
list shall not have an ellipsis terminator and the type of each
parameter shall be compatible with the type that results from the
application of the default argument promotions. If one type has a
parameter type list and the other type is specified by a function
definition that contains a (possibly empty) identifier list, both
shall agree in the number of parameters, and the type of each
prototype parameter shall be compatible with the type that results
from the application of the default argument promotions to the type of
the corresponding identifier. (In the determination of type
compatibility and of a composite type, each parameter declared with
function or array type is taken as having the adjusted type and each
parameter declared with qualified type is taken as having the
unqualified version of its declared type.)

So because one set of corresponding parameters are not compatible, the function types are not compatible.

Finally, section 6.5.2.2p9 regarding the function call operator () describes what happens in this case:

If the function is defined with a type that is not compatible with the
type (of the expression) pointed to by the expression that denotes the
called function, the behavior is undefined.

So calling a function through an incompatible function pointer type triggers undefined behavior and therefore should not be done.

Why do I need to avoid casting a function pointer to a generic pointer in this case?

There's no problem with your code, and there's also no problem with that passage in the book. The "problem" is that the passage doesn't apply to your code.

the book I'm reading mentioned that casting between "void *" and a "function pointer" is illegal.

This is true. See this question/answer.

But in your code you don't have a void*. foo.function is a void(*)() (a pointer to a function taking any number of arguments and returning void), which is the same type as func_pointer. So there's no need to do any sort of casting. foo.function = method; is correct.

Edit

From the clarifications you've added to your question, it seems like the book is saying something along the lines of: "With a void* we'd be able to avoid a lot of ugly casts between types, but since ANSI C doesn't allow void* to hold function pointers we can't avoid these casts."

Simplifying one of the examples from the book:

struct Class {
void * (*ctor)(const void * self, va_list * arg_ptr);
};
struct Class self;

typedef void (*voidf)();
voidf method = ...;

*(voidf*)&self.ctor = method;

That cast is necessary because self.ctor is a void* (*)(const void*, va_list*), not a void(*)().

If you could use a void* here, you could instead do:

void *method = ...;
self.ctor = method;

Without doing any casts.



Related Topics



Leave a reply



Submit