Hacker News new | ask | show | jobs
by flohofwoe 605 days ago
In C, all pointers are compatible to a void pointer without casting though (e.g. assigning a char pointer to a void pointer or the other way around is completely legal - I think that was the main reason why void pointers were added in the first place - it's basically an 'any pointer'). It's only C++ where this is an error (which is weird on its own, why even allow void pointers in C++ when the only reason they (presumably) exist doesn't work anymore).

The above code still doesn't compile in C because C complains about the function signatures being incompatible, even though the only difference is the argument type which itself is 'equivalent' in C - which I guess could be interepreted as an edge case in the C spec? (IMHO the function prototypes should actually be compatible).

3 comments

"Compatibility" has a specific meaning in C which isn't the same as what you're describing here. What you're talking about is implicit conversions without narrowing.

Compatibility is essentially about ABI: https://en.cppreference.com/w/c/language/type#Compatible_typ...

The C standard is quite loose about pointer requirements. Conversions between data pointers or between function pointers are allowed, but conversions between each other are not guaranteed. You can read the nitty gritty here: https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf

POSIX defines stricter requirements for pointers than the C standard. All pointers are compatible, so they have the same size and representation, and conversions between function pointers and void* are explicitly allowed.

Not all pointers. Function pointers, though often used that way, should not be cast to void. ISO C forbids it. (Implementations may allow it.)
ISO C forbids it, but, FWIW, POSIX requires it. So pick your standard I guess.
you can convert a short to an int without casting and it will roundtrip without loss of data; similarly you can roundtrip any data pointer through a void pointer without loss of data. It doesn't mean that an int has the same representation of a short or a void* has (necessarily) the same representation as any other pointer.

In C++ any pointer is also implicitly convertible to a void *, it is the reverse implicit conversion that is prohibited as it is not safe in the general case.

For consistency C++ should also prohibit implicit narrowing conversions (e.g. int to short ); I guess this was thought to break too much existing code and it is generally safer than a pointer conversion (although potentially lossy the behavior is fully defined). Many compilers will warn about it, and narrowing conversions are now prohibited in braced initialization.

Re implicit narrowing conversions, I think most compilers have warnings for this by now both in C and C++, at least in the higher warning levels.