Passing `int (*) (char const *)` where `int (*) (char *)` is expected

I have a pointer to a function whose function is declared as expecting char * arguments.Into, I would like to save a pointer to a function declared as taking char const* arguments.

I think I can use a wrapper or a toss. Castes seem more understandable, but can I legitimately name the result of such a function?

Sample code below:

 static int write_a(char * X){ return 0; } static int write_b(char const* X){ return 0; } static int wrapped_write_b(char * X){ return write_b(X); } typedef int (*write_fn)(char * ); write_fn a = write_a; write_fn b = wrapped_write_b; write_fn b1 = (write_fn)write_b; //is b1 legally callable? 
+6
source share
3 answers

Strictly speaking, this is prohibited.

A pointer-to-something incompatible with pointer-to-qualified-something . Since pointer-to-qualified-something not a qualified pointer-to-something

The same applies to

pointer-to-function-accepting-something

and

pointer-to-function-accepting-qualified-something .

This can be found through the C11 6.2.7 compatible type:

Two types have a compatible type if their types are the same. Additional rules for determining the compatibility of two types: described in 6.7.2 for type specifiers, in 6.7.3 for type classifiers ...

Where 6.7.3 is an important part. It says:

For two qualified types that must be compatible, both must have an identical version of the compatible type;

Conversion section 6.3.2.3 does not contradict this:

A pointer to a function of one type can be converted to a pointer to a function of another type and vice versa; The result is compared with the original pointer. If the converted pointer is used to call a function whose type is incompatible with the reference type, the behavior is undefined.

EDIT

As noted in Holt's answer, the compatibility of the two functions is explicitly described in 6.7.6.3/15 .


I still think the wrapper function is the best solution. The root of the problem is that write_a not const-correct. If you cannot change this function, write a wrapper around it.

+3
source

This behavior is undefined. You can use a pointer to call a function of another type only if the types are compatible ( 6.3.2.3 / 8):

A pointer to a function of one type can be converted to a pointer to a function of another type and vice versa; The result is compared with the original pointer. If the converted pointer is used to call a function whose type is incompatible with the reference type, the behavior is undefined.

Two functions have compatible types if (simplified version) they have the same return and arguments are compatible ( 6.7.6.3 , Semantics / 15)

For two types of functions that must be compatible, both must indicate compatible return types .146) In addition, lists of parameter types, if both are present, must match the number of parameters and the use of the terminator with ellipses; corresponding parameters must have compatible types.

A const char * incompatible with char * ( 6.7.6.1 , semantics / 2):

For two types of pointers that must be compatible, both must be equally qualified, and both must be pointers to compatible types.

Since const char * and char * not identical, they are incompatible, and calling write_b via b is undefined behavior.

+10
source

write_fn b1 = (write_fn) write_b; // is this legal?

Is it legal?

The types of function pointers involved in this cast are incompatible.

However, a cast function pointer to an incompatible type of function pointer is completely legal. However, the only thing you can do with such a strongly transformed pointer is to return it back to its original type. The language specification ensures that such a round-trip conversion preserves the original value of the pointer. That is why we can use, say, void (*)(void) as the "universal type of storage" for function pointers (for example, void * for data pointers). It can be used to store function pointers of any type (but not to call functions). To perform such a repository of pointers (and search), we will have to use explicit casts, as in your code. Nothing illegal there.

Meanwhile, an attempt to call a function through b1 will lead to undefined behavior, in particular, because the type of the pointer is incompatible with the actual type of the function.

In your question, you clearly state that you want to "save" a pointer to this function. While we are only talking about β€œsaving” (storing) a pointer, your code is completely flawless.

+2
source

Source: https://habr.com/ru/post/1012811/


All Articles