Why exactly can't function pointers be implicitly converted?
Asked Answered
B

1

-1

Rationale for C, Revision 5.10, April-2003:

It is invalid to convert a pointer to a function of one type to a pointer to a function of a different type without a cast.

It seems that they wanted to say "without an explicit cast".

Question: Why exactly is implicit conversion not allowed? To compare with: for integers implicit conversion is allowed.

UPD. The same question goes for object pointers.

Blueweed answered 10/1, 2022 at 14:28 Comment(19)
For additional protection? The number and type of arguments, and the function type, may not be congruent.Lexi
Type safety? C is lacking it, but here it is trying to do better, and people are complaining :)Famed
A cast is explicit by definition, so they wrote exactly what they mean. Conversions can happen implicitly or explicitly. When you want to explicitly cause a conversion, you write a cast in your code.Offload
AFAIK, standard does not require pointer to a function be interchangeable with a pointer to the data. Those types can have very different size and representationInterrex
@StoryTeller-UnslanderMonica Then why do they use "explicit cast" in the document?Blueweed
@Blueweed - It's a common misnomer, as a cursory search of the posts on StackOverflow will reveal. Even experts are not immune.Offload
"Explicit cast" isn't an incorrect term though, casts are always explicit. "Implicit cast" is incorrect.Confident
Formal definition of terms, C17 6.3 "Several operators convert operand values from one type to another automatically. This subclause specifies the result required from such an implicit conversion, as well as those that result from a cast operation (an explicit conversion)."Confident
@WeatherVane Then why no "additional protection" for integers?Blueweed
@Blueweed Because when a programmer is assigning one integer to another - it is pretty clear what they want - to have one the value of another (at least in majority of cases). When they assign one function pointer with incompatible another one - it is not that clear.Famed
@Confident Exactlly! If casts are always explicit, then "explicit cast" is a pleonasm.Blueweed
So kind of like people typing out superfluous keywords when coding, such as { auto int x; or extern void func (void);Confident
@Blueweed why no integer protection? We do get a compiler warning when assigning the value of a larger type to a smaller one without a cast (except among those with implicit type promotion).Lexi
@WeatherVane Hm, for long long ll = LLONG_MAX; int i = ll; both clang 13.0.0 and gcc 11.2.0 under -std=c11 -pedantic produce no warnings.Blueweed
For int i = ll; MS VC gives this warning: 'initializing': conversion from '__int64' to 'int', possible loss of data. Crank up your warning levels!Lexi
@StoryTeller-UnslanderMonica FYI: C standard itself uses "explicit cast".Blueweed
@Confident FYI: C standard itself uses "explicit cast".Blueweed
@Blueweed Yes I know, I actually checked before I wrote that comment. (It never uses "implicit cast" though) The only place where it is used in the actual standard is in 6.5.4 "Conversions that involve pointers, other than where permitted by the constraints of 6.5.16.1, shall be specified by means of an explicit cast." This goes hand in hand with my posted answer which mentions the very same situation, the rules of simple assignment. Meaning that assignment is the only place where pointer conversions without a cast can take place.Confident
@Confident Note that the standard may be a subject of editing errors, typos, etc. Example: hexadecimal floating-point constant vs. hexadecimal floating constant.Blueweed
C
3

There are implicit and explicit conversions. A cast is always an explicit conversion and uses the (type) cast operator.

C has quite decent type safety when it comes to pointers. Apart from the special case of null pointer conversions, the only implicit pointer conversion allowed is between an object pointer and a pointer to void. Given that no type qualifiers are dropped. void* is not a generic type for function pointers though - no such type exists. As per C17 6.3.2.3/8, it's fine to convert between different function pointer types though, as long as the pointer is de-referenced with the correct type.

The specific rules for what's allowed and what isn't is found in C17 6.5.16.1 - Simple assignment. An assignment that fulfil the rules there would implicitly invoke the applicable conversion rule and it's a so-called "lvalue conversion" basically meaning that you can add type qualifiers to the left operand but you can't discard qualifiers present for the right operand.

Generally, 6.3.2.3 says what kind of conversions that can be done in general and 6.5.16.1 says what conversions that are allowed to be carried out implicitly during assignment.

To allow implicit conversions between various integer and floating point types is arguably a design flaw in the C language - it's a constant source of subtle and often severe bugs. Why C++ decided to fix it by enforcing explicit conversions everywhere. So the real question here is perhaps rather: why does C allow implicit conversions of some types?

Confident answered 10/1, 2022 at 14:51 Comment(3)
Re: "why does C allow implicit conversions of some types?": exactly! For example, why C has quite decent type safety when it comes to pointers, but hasn't quite decent type safety when it comes to, for example, integers?Blueweed
Re: "C++ decided to fix it by enforcing explicit conversions everywhere": hm, for double d = DBL_MAX; int i = d; I don't get any diagnostics from g++ 11.1.0 nor from clang++ 12.0.0, both running under -std=c++17 -pedantic.Blueweed
@Blueweed Basically, C has lots of language flaws but they are all well-known, as are the work-arounds. One of the advantages of using an old programming language.Confident

© 2022 - 2024 — McMap. All rights reserved.