How to cast a function pointer to a void* a slightly-too-long-for-twitter report about a subtlety in C++
Question: How do you cast a function pointer to a void*? (You’re trustworthy and wouldn’t dare to do anything evil with it, right?)
Answer: Maybe your first thought was, well reinterpret_cast<void*>(&f)
of course. That was mine, at least. Well, it turns out, C++ wants to support architectures, where data and instruction pointers are physically distinct things. That’s why the standard forbids casting of function pointers to data pointers.
Many compilers will accept it anyhow and just emit a warning, but there’s a trick, which doesn’t rely on compiler specifics: A reference to a function pointer is a data reference (because of course a function pointer itself is data, even if it’s pointing to instructions) and thus it can be cast to void*&
, which in turn can be assigned to a void*
.
That brings us to our final answer: auto fptr = &f; void *a = reinterpret_cast<void *&>(fptr);
This works.
Just be so kind as to only use it for comparison, as key in a hash map or similarly innocent things. Do not dereference it or you will enter the myth-enshrouded lands of undefined behavior.
——-
P.S. There are two caveats to be made:
1. Even though this is guaranteed to work with all standard-compliant compilers, it’s not guaranteed to be safe on all platforms. On machines with Harvard architecture, the size of a function pointer often differs from the size of a void*
(e.g. 16bit on the Arduino One). So, especially if you’re developing for micro controllers, double check before using this trick.
2. This is about pointers to _free_ functions. Pointers to member functions are strange creatures and, even on Von-Neumann architectures, don’t have the size of void*
. It’s not possible to squeeze a PMF into a void*
. (I’m happy to stand proven wrong).
blogs.msdn.microsoft.comPointers to member functions are very strange animals. Warning: The discussion that follows is specific to the way pointers to member functions are implemented by the Microsoft Visual C++ compiler. Other compilers may do things differently. Well, okay, if you only use single inheritance, then pointers to member functions are just a pointer to the…
POSIX requires reinterpret_cast(&f) to work because dlsym returns void*.
See http://pubs.opengroup.org/onlinepubs/9699919799/functions/dlsym.html
Note that conversion from a void * pointer to a function pointer as in:
fptr = (int (*)(int))dlsym(handle, “my_function”);
is not defined by the ISO C standard. This standard requires this conversion to work correctly on conforming implementations.
On my platform, which is 65816/SNES albeit smarter, PMFs are 3-bytes address, and MSB of the 4th is clear. Otherwise they are 2-byte offsets into the vtable with 15 padding bits. There’s your platform where pointers to free functions are compatible with PMFs. Also PFs are 3-byte addresses with a padding byte in the back because having a sizeof (3) is probably awkward, same with regular pointers.