4 ms·
This is also untrue, if the standard did mandate that pointers to functions could participate in a memcpy and the behavior was as if the instructions of that fu
by Kranar 5y ago
This is also untrue, if the standard did mandate that pointers to functions could participate in a memcpy and the behavior was as if the instructions of that function were treated as an array of chars, then C++ compilers would be forced to accommodate that implementation regardless of what platform it ran on, Itanium, x86, even a PDP-11 it wouldn't matter. For example it might mean that implementations must tag or otherwise store a dictionary to keep track of addresses to functions so as to differentiate pointers to functions from pointers to objects and produce whatever appropriate behavior is needed to copy said instructions. An implementation could keep an intermediate representation of any function that can potentially be memcpy'd and then translate that representation at runtime when it participates in a memcpy. Whatever the case may be, if the standard mandates certain behavior then an implementation is required to respect it. While not entirely the same, C++ does do something along these lines in certain situations involving pointers to virtual member functions involved in a diamond inheritance structure.
Saying that C++ (the code in the article is not C and the two languages differ about the treatment of pointers to functions) could have well defined semantics to handle this is entirely moot... it's about as relevant as saying that a C++ program could run on top of the JVM with a garbage collector [1] and hence eliminate all types of memory errors. Even if a C++ program ran on a platform that had guaranteed garbage collection the fact would still remain that C++ as a language does not have well defined semantics for what happens to a dangling reference and as such a C++ compiler is free to exploit that to make very strong assumptions about the runtime behavior of the program for the sake of generating efficient code.
The fact that this is undefined behavior gives a compiler the freedom to perform optimizations under the assumption that runtime behavior will never engender said behavior. Raymond makes use of this property when he discusses COMDAT folding which is a common optimization to elide multiple copies of the same function or to even produce multiple versions of a single function optimized for different scenarios. From the article:
"Even without Profile-Guided Optimization, compile-time optimization may inline some or all of a function, so a single function might have multiple copies in memory, each of which has been optimized for its specific call site."
This property has nothing to do with x86, or Itanium or PDP-11, it's a purely logical optimization permissible only because of the various forms of undefined behavior in C++ with respect to the treatment of function pointers.
[1] http://nestedvm.ibex.org/ http://nestedvm.ibex.org/
- anticensor 5y ago> if the standard did mandate that pointers to functions could participate in a memcpy and the behavior was as if the instructions of that function were treated as an array of chars, then C++ compilers would be forced to accommodate that implementation C/C++ compilers would then not be portable to ISAs with Harvard architecture.