user1142353
user1142353

Reputation: 51

Compilation warning due to mismatch in function pointer type definition and assigned function with correct const logic

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?

  1. Define the function like above and ignore the warning.
  2. "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

Answers (2)

Jon Purdy
Jon Purdy

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

Ben Voigt
Ben Voigt

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

Related Questions