Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reason why int(*g)(int) into int(*h)(char) causes error?

Tags:

c++

c

I am studying programming language principles and I have a question with C and C++.

int (*f)(int);
int (*g)(int);
int (*h)(char);

f = g; // ok
h = g; // warning in C, error in C++

Assigning g into f (f = g) will not cause an error in C or C++, but assigning g into h (h = g) would generate a compiler warning in C and compile error in C++.

I heard that the char type is usually auto-casted into int in C++, so I thought this would not cause an error.

Can someone explain this to me?

like image 659
Jackie Avatar asked Jan 25 '23 15:01

Jackie


2 Answers

Assigning g into f (f = g) will not cause an error in C/C++, but assigning g into h (h = g) would generate a compiler warning in C and compile error in C++.

This is incorrect. A program that attempts to do h = g is an invalid program, be it C or C++. However the C standard explicitly mentions that a C compiler is allowed to successfully compile an invalid program, provided that it issues a diagnostic message for every violation of certain rules. You got your warning and then the C compiler proceeded anyhow.

In fact, C++ standard contains a very similar wording:

If a program contains a violation of any diagnosable rule or an occurrence of a construct described in this document as “conditionally-supported” when the implementation does not support that construct, a conforming implementation shall issue at least one diagnostic message.

[...]

A conforming implementation may have extensions (including additional library functions), provided they do not alter the behavior of any well-formed program. Implementations are required to diagnose programs that use such extensions that are ill-formed according to this document. Having done so, however, they can compile and execute such programs.

But customarily C++ compilers are by default more strict when it comes to diagnosable violations and the compilation will fail by default whereas the C compiler from the same vendor would successfully compile such a translation unit.


Note that both C and C++ has a provision that you can do the conversion with a cast, i.e. h = (int (*)(char))g; but you again must not call a function through h without casting it back to int (*)(int) first!

like image 123

For two function types to be compatible, the returns types must match and the number and types of the arguments must match. The conversion rules that apply between integer types do not apply to arguments of function types.

Section 6.7.6.3p15 of the C standard states the following:

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 types int and char are not compatible with each other, therefore a function with one int parameter and another with one char parameter are not compatible with each other, making the assignment in your example invalid.

C compilers will typically warn when attempting a conversion between incompatible pointer types. Attempting to defererence h in your example by calling the function will invoke undefined behavior.

like image 30
dbush Avatar answered Jan 31 '23 11:01

dbush