In my code I'm trying to use dummy objects to perform modularity in C.
At the moment I specify important function useful for every objects via function pointers, like destructors, toString, equals as follows:
typedef void (*destructor)(const void* obj); typedef void (*to_string)(void* obj, int bufferSize, const char* buffer); typedef bool (*equals)(void* obj, const void* context); In my code base then I use function pointer compatible to the given typedef to abstractly handle objects, for example:
struct Foo { int a; } Foo; void destroyFoo1(const Foo* p) { free((void*)p); } int main() { //... Foo* object_to_remove_from_heap = //instance of foo destructor d = destroyFoo1; //somewhere else d(object_to_remove_from_heap, context); } The code compiles and normally it would generate only a warning (destructor first parameter should be a const void* but instead it is a const Foo*).
However, since I've enabled -Werror, the "invalid pointer cast" is treated as an error. To solve this issue, I need to cast the function pointer, as follows:
destructor d = (destructor)destroyFoo1; I know per standard const void* and const Foo* may have different memory size, but I assume the platform where the code is deployed const void* and const Foo* are allocated in the same memory space and have the same size. In general I assume the cast of function pointer where at least one pointer argument is changed into some other pointer is a safe casting.
This is all good but the approach shows its weakness when, for example, I need to change the signature of destructor type, for example by adding a new const void* context parameter. Now the interesing warning is silenced and the number of parameters in the function pointer call mismatch:
//now destructor is typedef void (*destructor)(const void* obj, const void* context); void destroyFoo1(const Foo* p) { free((void*)p); } destructor d = (destructor)destroyFoo1; //SILCENCED ERROR!!destroyFoo1 has invalid parameters number!!!! //somewhere else d(object_to_remove_from_heap, context); //may mess the stack My question is: is there a way to check if a function pointer can indeed be safely casted into another (and generating a compile error if not)?, something like:
destructor d = CHECK_IF_FUNCTION_RETURNS_VOID_AND_REQUIRE_2_VOID_POINTERS(destroyFoo1); Something that if we pass destroyFoo1 everything is fine but if we pass destroyFoo2 the compiler complains.
Below a code that summarizes the problem
typedef void (*destructor)(const void* obj, const void* context); typedef struct Foo { int a; } Foo; void destroyFoo1(const Foo* p, const void* context) { free((void*)p); if (*((int*)context) == 0) { printf("hello world\n"); } } void destroyFoo2(const Foo* p) { free((void*)p); } int main() { //this is(in my case) safe destructor destructor = (destructor) destroyFoo1; //this is really a severe error! //destructor destructor = (destructor) destroyFoo2; Foo* a = (Foo*) malloc(sizeof(Foo)); a->a = 3; int context = 5; if (a != NULL) { //call a destructor: if destructor is destroyFoo2 this is a SEVERE ERROR! //calling a function accepting a single parameter with 2 parameters! destructor(a, &context); } } Thanks for any kind of reply
-Wbad-function-castoptionCALL_MAYBEmacro objective is to automatically check the nullness of the function pointer, not deal with the correct/wrong number of parameters.-Wbad-function-cast: I've tried on the MWE I've provided and it doesn't generate an error (the warning generated is-Wincompatible-pointer-types)