With normal functions, one can write
extern "C" int Frotz(int); // in a header
int Frotz(int x) { return x; }
With function pointers, however, this appears to have been implemented inconsistently between compilers.
extern "C" int Klutz(int (*)(int), int);
int Klutz(int (*fptr)(int), int x) { return (*fptr)(x); }
In the declaration, the argument is also extern "C"
. In the definition, most compilers appear to match these functions and make Klutz
an extern "C"
function. The Sun and Cray compilers, however, interpret these functions as being different, producing an overloaded int Klutz(int (*fptr)(int), int x)
, which later generates a link-time error.
Although Section 7.5.5 of C++98 and C++11 guarantees the interpretation of Frotz
, I cannot tell if the standard is ambiguous about whether extern "C"
matching should occur before or after checking for overloading.
Should Klutz
above generate a mangled (C++) symbol or an extern "C"
symbol?
EDIT 1
I could use a typedef to disambiguate the function pointer to have C or C++ ABI, but I'm interested in whether the code here (a) defines Klutz
to have C++ linkage, (b) defines it to have C linkage, or (c) is ambiguous according to the standard, so that compilers are free to choose how to interpret it.
EDIT 2
This appears to be a known issue, at least by those compilers with searchable bug trackers. In my tests, GCC, Clang, Intel, MSVC, IBM XL, PathScale, PGI, and Open64 all fail to distinguish function types that are identical except for language linkage, as explicitly required by the standard (see section 7.5.1, quoted in the accepted answer). Fixing this would break a lot of existing code and require an ABI change. I'm not aware of any compiler that actually uses a different calling convention for C versus C++ language linkage.
GCC bug: "Finding reasons to ask for the removal of this feature from the next standard is kind of relevant ;-)" ... "And we may even decide on an official WONTFIX."
Clang bug: "I'm terrified of actually enforcing this rule, because doing it properly means making language linkage part of the canonical type, which is going to break a ton of code."