#include
double log(double) {return 1.0;}
int main() {
log(1.0);
}
Suppose the function log()
in
If extern "C" double log(double)
is initially declared in the global namespace, then you have redeclared it and provided a definition. The implementation's previous mention of extern "C"
carries over to your matching redeclaration. Your definition applies to the function belonging to the implementation, and it is an ODR violation.
As for the manifestation of UB: It's apparently common to treat log
as a weak linker symbol. Your implementation overrides libc.so
according to ABI rules.
(If the implementation doesn't do extern "C"
, it's still basically all the same.)
If log
is declared in namespace std
and then brought into the global namespace, then your declaration will conflict with it. (Actually, a using
declaration is technically a declaration.) This error is diagnosed.
then it refers to the same function as the
log
function we defined
One way for the implementation to put
names into the global namespace would be to declare extern "C"
functions inside namespace std
, then do using namespace std
, and to ensure that this always happens as the first thing when any standard header is included. Since using namespace
isn't "sticky" — it only applies to preceding declarations in the nominated namespace — the rest of the standard library would not be made visible. (This would not declare the names in the global namespace, but the standard only says "placed within the global namespace scope.")
In such an implementation, your declaration would hide the standard one and declare a new function with a new mangled name (say _Z3logd
instead of simply log
) and a new fully-qualified name (::log
instead of ::std::log
). Then there would be no ODR violation (unless some inline function uses one log
in one TU and the other in a different TU).