Search code examples
cpointersfunction-pointersgcc-warning

Getting incompatible pointer type warning because the return of the function is not void* but a struct pointer


This warning seems to not be necessary. In my code, I have a function pointer type

(void*)(*function_pointer)(void* data)

and some functions require function pointers of this type as a parameter, because they do not depend on the return type, it just has to be a pointer.

But, when I pass a function like somestruct* function_A(void* data) to it, I get that warning, even though somestruct* could be implicity converted to void*, the same way that I can pass to a function int function_test(void* data) a somestruct pointer and it would work without warnings.

Yes I can define function_A with a void * as return type, but it would mean everyone who will use that function for other reasons will have to cast its return value to somestruct *. I have these two options: leave as it is and ignore the warning which annoys me a bit, or change the function definition, which would annoy me even more.

So here I am, asking if there is a third option.


Solution

  • It is allowed to convert any object pointer to a void * and back, however that does not carry over to arguments and return types in function pointers.

    A pointer to function somestruct* function_A(void*) is not compatible with a function pointer of type void* (*function_pointer)(void*) because the return types are not compatible. Attempting to call a function through an incompatible pointer type will trigger undefined behavior.

    The rules regarding how to determine if two function types are compatible are spelled out in section 6.7.6.3p15 of the C standard:

    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.)

    The portion in bold is what's relevant in this particular case. A void * and and struct pointer are not compatible, even though it's allowed to convert between the two.

    The rules of function pointer conversions are spelled out in section 6.3.2.3p8:

    A pointer to a function of one type may be converted to a pointer to a function of another type and back again; the result shall compare equal to the original pointer. If a converted pointer is used to call a function whose type is not compatible with the referenced type, the behavior is undefined.

    With the last section in bold stating that what you're attempting to do is not allowed.

    You'll need to change the return type of your function to void * to be compatible with the function pointer type. Casting the return type however is not necessary, as conversions between an object pointer and a void * is allowed without one.