Possible ambiguity with extern "C", overloading, and function pointers - c++

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:
extern "C" {
typedef int (*KlutzFuncType)(int);
int Klutz (KlutzFuncType, int);
}
int Klutz (KlutzFuncType fptr, int x) { return (*fptr)(x); }
There is some discussion of this issue here.
I only have a copy of the draft. From 7.5p1:
Two function types with different language linkages are distinct types even if they are otherwise identical.
My reading of this is that the first parameter of your first Klutz has a different type than the first parameter of your second Klutz, and so your second Klutz 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, while KlutzCFuncType refers to a function with C linkage.
typedef int (*KlutzCxxFuncType)(int);
extern "C" {
typedef int (*KlutzCFuncType)(int);
int Klutz (KlutzCFuncType, int);
}
int Klutz (KlutzCxxFuncType fptr, int x) { return (*fptr)(x); }
int Klutz (KlutzCFuncType fptr, int x) { return (*fptr)(x); }
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:
prog.cpp: In function ‘int Klutz(KlutzCFuncType, int)’:
prog.cpp:9:5: error: redefinition of ‘int Klutz(KlutzCFuncType, int)’
prog.cpp:8:5: error: ‘int Klutz(KlutzCxxFuncType, int)’ previously defined here

Related

Conflicting declaration of function with ‘C’ linkage

Following compiles without error:
extern "C" void func( void );
extern void func( void );
If I change order of declarations,
extern void func( void );
extern "C" void func( void );
I get compiler error: conflicting declaration of ‘void func()’ with ‘C’ linkage.
C++ standard says:
At most one function with a particular name can have "C" linkage (regardless of namespace)
In both cases it is the same function. My assumption is that C++ compiler stores internally functions signature it will compile. In first example, compiler consideres second declaration as valid and uses first declaration to compile. In second example it is not the case. It regrads both declarations as diferent declaration.
What are technical details behind it?
gcc 9.4.0 and msvc 19.29.30147
Re-declarations of a function are not required to repeat their linkage specification. Per Language linkage from cppreference:
A function can be re-declared without a linkage specification after it was declared with a language specification, the second declaration will reuse the first language linkage. The opposite is not true: if the first declaration has no language linkage, it is assumed "C++", and redeclare with another language is an error.
In the first snippet, you declare a function with "C" linkage and then later re-declare it with no explicit linkage. This is okay; the original linkage is assumed. However, in the second snippet, you declare a function with (implicit) "C++" linkage, and then later attempt to re-declare it with "C" linkage---that's a conflict, hence the error.

how does overloading with C linkage work in C++?

Consider this example:
int foo(void);
extern "C" int foo(void);
int main()
{
return foo();
}
It errors out with:
$ g++ -c main.cpp
main.cpp:2:16: error: conflicting declaration of ‘int foo()’ with ‘C’ linkage
2 | extern "C" int foo(void);
| ^~~
main.cpp:1:5: note: previous declaration with ‘C++’ linkage
1 | int foo(void);
| ^~~
Which is perfectly fine.
But lets swap first 2 lines:
extern "C" int foo(void);
int foo(void);
int main()
{
return foo();
}
Now it compiles without any error,
but the C linkage is chosen, even
though C++ linkage is found the last.
Questions:
Why case 2 compiles and case 1 fails? I would expect them to behave the same way.
For the case 2 which compiles, why C linkage is chosen and is it possible to change that?
Background:
I have a C++ program where the function name occasionally
clashed with the one in a C standard library. I would
expect an error in such case, but it compiled fine and
the wrong linkage was chosen. I need to either find a
way of making it to fail consistently (to fix all such
cases), or to force the selection of a C++ linkage for
all conflicting functions.
extern "C" int foo(void);
int foo(void);
Here foo is declared with extern "C". Re-declaration does not specify a different calling convention, so no problem.
But,
int foo(void);
extern "C" int foo(void);
Here first line does not explicitly specify calling convention, so default C++ is implicitly chosen. Then second line does explicitly specify a different calling convention, creating a conflict.
So question 2... It is not possible to change calling convention after it is set by first declaration.
How to solve the problem... Use a different name for your C++ function. Or put it in a namespace. Or maybe isolate conflicting C++ name in a separate .cpp file, and export a different function (or just function pointer) for calling it elsewhere (see last paragraph below).
Another solution is to be careful about #include order, so the C++ function is always declared first. There is no "nice" solution to this, other than being pedantic about include order.
The only proper, valid solution is not have any symbols, which conflict with anything in C++ standard library. That is not allowed by C++ standard. Rename your own functions, or put them in your own namespace.
An important detail is, that the linker symbol for these functions is different. C++ does symbol name mangling to enable namespaces, methods and overloading. So it is possible for both functions to exist and be callable in a linked/running program. Problem is only at source code level.

Problem with using C code in C++ with extern "C"

I know when i want to link C code as C code in C++ should i use extern "C". But with the following code :
/* file.h */
some (void)
{
return 10;
}
extern "C"
{
#include "file.h"
}
#include <iostream>
int main (void)
{
std::cout << some() << std::endl;
}
I get this compile time error:
C4430: missing type specifier - int assumed. Note: C++ does not support defualt-int.
How i can deal with this ?
I use MSVC2017 on MS-Windows10.
EDIT: I know that most declare the function with a explicit return type, But i what to use USBPcap and USBPcap declare some function like that. How i can use it in my own C++ program ?
All functions should specify a return type. You aren't specifying one for some.
In older versions of C, if you omit the return type of a function it defaults to int. C++ however doesn't support that.
You should always specify a function's return type:
int some(void)
{
return 10;
}
extern "C" only changes the linkage of declarations. In particular, it disables C++ name mangling that is otherwise needed for some C++ features such as overloading.
extern "C" does not make the enclosed part of the program to be compiled as C. As such, the declarations must still be well-formed C++. some (void) is not a well-formed declaration in C++, which explains the error.
How i can deal with this ?
Declare the return type explicitly.
USBPcap declare some function like that. How i can use it in my own C++ program ?
Then you cannot use that header. You can write a C++ compatible header yourself. Or, you can use a C++ compiler that supports impilict int as an extension.
P. S. Implicit int is not well-formed in C language either since C99.
Do not put any code to the .h files except static inline functions
Secondly declare the functions correctly - not the lazy way. What is some(void)? If the C++ compiler knew the return type of the function ....
extern "C"
{
int some (void)
{
return 10;
}
}
#include <iostream>
int main (void)
{
std::cout << some() << std::endl;
}
https://godbolt.org/z/_AJgFX
The compiler have say to you exactly what is the problem. The function that you are trying to call from std::cout need to have a returned type explicitly defined. In C the compiler automatically set the return type of an undefined-type function to int and you can compile a code that contain untyped function with nothing more of a warning from the compiler , but not do it, it is extremely wrong way to write code. In C++, just like the compiler told you, you can't, so it is an error. The definitions in C and C++ must have a type, if you want a function that not return anything, you need define it void.
However, in the last versions of the c++ standards you can use the auto keyword to auto detect the type of a declaration at compile time, so if you want that the compiler auto detect the type of something, use it, but use it with sparingly.
So, finally, if you want write C or C++ code, please, add a type to your definitions, this isn't python or javascript...

Is it possible to overload functions with extern linkage?

I saw a strange code, in declaration of std::atexit:
extern "C" int atexit( void (*func)() );
extern "C++" int atexit( void (*func)() ); // ... why are there two functions?
I guess it's some kind of function overloading, but it seems obviously wrong.
What's it? and why is it necessary?
The problem with your source
This is cppreference being a little misleading.
Declaring the same function twice with different storage-class-specifiers is illegal and causes a build failure. If you look at the source for libstdc++ (GCC's standard library implementation), you'll see that only the extern "C" version is actually provided.
The standard's take on this
Although [C++11: 18.5] lists both declarations, just as does cppreference, this does not mean that both may be used in a single implementation; it means that an implementation may choose to declare either of them: that is, it accounts for [C++11: 17.6.4.3.3/4] which says:
Each function signature from the Standard C library declared with external linkage is reserved to the implementation for use as a function signature with both extern "C" and extern "C++" linkage [..]
Also:
[C++11: 17.6.2.3/2]: Whether a name from the C standard library declared with external linkage has extern "C" or extern "C++" linkage is implementation-defined. It is recommended that an implementation use extern "C++" linkage for this purpose
The rule is made explicitly clear here:
[C++11: 7.5/5]: If two declarations declare functions with the same name and parameter-type-list (8.3.5) to be members of the same namespace or declare objects with the same name to be members of the same namespace and the declarations give the names different language linkages, the program is ill-formed; no diagnostic is required if the declarations appear in different translation units. [..]
Why this can be confusing
To my mind, this does cause some problems in other places within the standard; for example:
[C++11: 25.5/2]: The contents are the same as the Standard C library header <stdlib.h> with the following exceptions:
[C++11: 25.5/3]: The function signature:
bsearch(const void *, const void *, size_t, size_t,
int (*)(const void *, const void *));
is replaced by the two declarations:
extern "C" void *bsearch(const void *key, const void *base,
size_t nmemb, size_t size,
int (*compar)(const void *, const void *));
extern "C++" void *bsearch(const void *key, const void *base,
size_t nmemb, size_t size,
int (*compar)(const void *, const void *));
both of which have the same behavior as the original declaration.
I consider that to be a language defect.
I think you can not see such a code. At least there might be preprocessor directives similar to #if or #ifdef that separate these two declarations because according to the C++ Standard
5 If two declarations declare functions with the same name and parameter-type-list (8.3.5) to be members of the same namespace or declare objects with the same name to be members of the same namespace and the declarations give the names different language linkages, the program is ill-formed; no diagnostic is required if the declarations appear in different translation units. Except for functions with C++ linkage, a function declaration without a linkage specification shall not precede the first linkage specification for that function. A function can be declared without a linkage specification after an explicit linkage specification has been seen; the linkage explicitly specified in the earlier declaration is not affected by such a function declaration.

Overload resolution with extern "C" linkage

In a mixed C/C++ project, we need to make a call from C to a C++ function. The function to be called is overloaded as three separate functions, but we can ignore that from the C-side, we just pick the one most suitable and stick to that one.
There's two ways to do this: (1) write a small C++ wrapper with a extern "C" function that forwards the call to the chosen overloaded function, or (2) the hackish way to just declare the one function we want to call from C as extern "C".
The question is, is there any disadvantages (apart from nightmares and bad karma) to go for the second variant? In other words, given three overloaded function, where one is declared as exern "C", should we expect trouble with the C++ side, or is this well defined according to the standard?
I believe the language in the standard is specifically written to allow exactly one function with "C" linkage, and an arbitrary number of other functions with "C++" linkage that overload the same name (§[dcl.link]/6):
At most one function with a particular name can have C language linkage. Two declarations for a function with C language linkage with the same function name (ignoring the namespace names that qualify it) that appear in different namespace scopes refer to the same function. Two declarations for an object with C language linkage with the same name (ignoring the namespace names that qualify it) that appear in different namespace scopes refer to the same object.
The standard shows the following example:
complex sqrt(complex); // C + + linkage by default
extern "C" {
double sqrt(double); // C linkage
}
Even if it was allowed by the standard, future maintainers of the code will probably be extremely confused and might even remove the extern "C", breaking the C code (possibly far enough later that the events aren't linkable).
Just write the wrapper.
EDIT:
From C++03 7.5/5:
If two declarations of the same
function or object specify different
linkage specifications (that is, the
linkage specifications of these
declarations specify different
string literals), the program is
ill-formed if the declarations appear
in the same translation unit, and the
one definition rule (3.2) applies if
the declarations appear in different
translation units...
I interpret this to not apply since C and C++ functions with the same name aren't actually the same function but this interpretation may be wrong.
Then from C++03 7.5/6:
At most one function with a particular
name can have C language linkage...
This then implies that you could have other, non-C-linkage, functions with the same name. In this case, C++ overloads.
As long as you follow the other rules for extern-C functions (such as their special name requirements), specifying one of the overloads as extern-C is fine according to the standard. If you happen to use function pointers to these functions, be aware that language linkage is part of the function type, and needing a function pointer to this function may decide the issue for you.
Otherwise, I don't see any significant disadvantages. Even the potential disadvantage of copying parameters and return value can be mitigated by compiler- and implementation-specifics that allow you to inline the function – if that is determined to be a problem.
namespace your_project { // You do use one, right? :)
void f(int x);
void f(char x);
void f(other_overloads x);
}
extern "C"
void f(int x) {
your_project::f(x);
}
(This answer applies to C++14; other answers so far are C++03).
It is permitted to use overloading. If there is an extern "C" function definition of some particular name then the following conditions apply (references to C++14 in brackets):
The declaration of the extern "C" function must be visible at the point of any declaration or definition of overloads of that function name (7.5/5)
There must be no other extern "C" definition of a function or variable with the same name, anywhere. (7.5/6)
An overloaded function with the same name must not be declared at global scope. (7.5/6)
Within the same namespace as the extern "C" function, there must not be another function declaration with the same name and parameter list. (7.5/5)
If any violation of the above rules occurs in the same translation unit the compiler must diagnose it; otherwise it is undefined behaviour with no diagnostic required.
So your header file might look something like:
namespace foo
{
extern "C" void bar();
void bar(int);
void bar(std::string);
}
The last bullet point says that you cannot overload solely on linkage; this is ill-formed:
namespace foo
{
extern "C" void bar();
void bar(); // error
}
However you can do this at different namespaces:
extern "C" void bar();
namespace foo
{
void bar();
}
in which case , normal rules of unqualified lookup determine whether a call bar() in some code finds ::bar, foo::bar, or ambiguous.