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."
The C ABI and the C++ ABI are not guaranteed to be the same. So, an
extern "C"
function pointer is a different type from a C++ function pointer. You need something like this:There is some discussion of this issue here.
I only have a copy of the draft. From 7.5p1:
My reading of this is that the first parameter of your first
Klutz
has a different type than the first parameter of your secondKlutz
, and so your secondKlutz
should have C++ linkage.There are C++ implementations that do not take language linkage into account for function types, despite what the standard says. In the following code snippet,
KlutzCxxFuncType
refers to a function with C++ linkage, whileKlutzCFuncType
refers to a function with C linkage.A compiler that does not distinguish function types based on language linkage will generate a redefinition error on this code. For example,
g++ 4.7.2
will emit: