Reputation: 51
I am using an external library in a project that I am working on. It is written in C. In the external library, the following is defined:
typedef void* (*foo_fn) (void *arg1, void *arg2);
One of library's API/function takes the function pointer (of the above type) as input.
Now, in my module, I am implementing a function as mentioned below, as I know that would make more sense for this function's logic:
void * foo_fn (const void* const arg1, void* const arg2);
When I pass in this function's pointer to the API, I get the following warning:
warning: assignment from incompatible pointer type
I understand the reason behind the above warning, but I would like to know which of the following is the right thing to do?
"Strictly adhere" to the external library's expectation and ignore the logic that would make sense for my function and define the function as below?
void * foo_fn (void* arg1, void* arg2);
Upvotes: 3
Views: 692
Reputation: 54979
If the library expects a callback with arg1
of type void*
, then passing a callback with a parameter of type const void*
is permissible—your callback makes the extra guarantee of not modifying its input, but the library doesn’t care either way.
So you have two options: safely define foo_fn
with const
qualification and give the library a function without const
that calls the const
version:
void* foo_fn(const void* const arg1, void* arg2);
void* foo_fn_non_const(void* arg1, void* arg2) {
return foo_fn(arg1, arg2);
}
library_fn(foo_fn_non_const);
Or unsafely cast the function pointer type:
library_fn(reinterpret_cast<void* (*)(void*, void*)>(foo_fn));
This makes one mildly unsafe assumption: that const void*
has the same calling convention as void*
.
Upvotes: 0
Reputation: 283664
Even though the function conforms to the required signature under computer-science notions of the LSP, the pointer is adding a const
-qualification (which is safe), and the pointer types are strictly required to be representation- and layout-compatible (this is implied by being able to store &px
where X* px;
in a variable of type const X* const* const
, which is legal), in C++ the function pointer types are different and calling through a function pointer of wrong type is undefined behavior.
This is important because it gives the optimizer special permission to break code that does this, even though a naive (unoptimized) compilation would generate working code on any architecture.
For example, if there's only one function in the entire program of the type that actual matches the function pointer, the optimizer could create a direct call to that function (or even inline it), ignoring the address actually in the function pointer. (Platforms which allow dynamic loading complicate this, but in some cases use of types with local linkage could exclude dynamically loaded functions from matching the signature)
Upvotes: 2