I've got C++ functions that I want to declare using extern "C" even though they are only called in C++ code. Yes, I know this is strange but it's something I would like to do for consistency since we have mixed C and C++ declarations. I just want to make sure that declaring a C++ function as extern "C" won't affect the behavior of throwing.
It would look something like this:
extern "C" void foo() {throw exception;}
int bar()
{
try
{
foo();
} catch (exception e) { return 1; }
}
"Can C++ functions marked as Extern āCā throw?"
Yes, in the sense that neither the language nor the compiler will prevent you from doing so.
No, in the sense that if you throw, it would be an undefined behaviour, as the C++ exception crosses language boundaries.
In practice: do not do it. Catch the exception and translate it into an error code, or a means the other language can understand.
So the bottomline is: do NOT throw exception from functions marked as extern "C".
For GCC the answer seems inconclusive.
The MSVC documentation, however is relatively clear on the subject:
/EHa and /EHs ... tells the compiler to assume that functions declared as extern "C" may throw an exception.
/EHsc ... tells the compiler to assume that functions declared as extern "C" never throw a C++ exception
So for Visual-C++ it depends on the compiler options whether you get defined behavior.
it will compile but it is undefined behavior to throw from function marked as having C linkage. C doesn't have exceptions, therefore in general you should just return an error code and/or provide a function that returns the information about the last error.
#include <exception>
extern "C" void foo() {throw std::exception();}
compiles well
Here is answer for your question: http://yosefk.com/c++fqa/mixing.html#fqa-32.6
Basically you won't be able to catch it. (but why you won't just compile it and try? :))
Related
I was presented with a C++ DLL source code that uses extern "C":
extern "C"
{
class Something
{
public:
__declspec(dllexport) Something();
__declspec(dllexport) virtual ~Something();
__declspec(dllexport) bool function_one(const char * some_text);
static __declspec(dllexport) char * get_version();
private:
unsigned int m_data;
};
}
The DLL is being called by a C++ program.
FYI, using Visual Studio 2017 on Windows 7 platform.
Questions *(all related to the extern "C" and class):
Since class is not C language, will this be equivalent to a
struct?
Are constructors valid?
Are virtual destructors valid (since C doesn't have virtual)?
How is the bool handled?
How is static treated inside the extern "C" for the class?
How is private data handled inside the extern "C" block?
How is noexcept handled in an extern "C" block for the
constructor?
The Visual Studio 2017 compiler is not generating any errors or warnings with the above code.
The VS2017 code analyzer only generates a warning for the constructor:
C26439 This kind of function may not throw. Declare it 'noexcept' (f.6).
Research:
The questions on StackOverflow related to this issue mention that the "extern "C"has the effect of resolving name mangling. However, they don't address the issues ofvirtual,bool`, private data, and etc. as I listed above.
Also, many DLLs related answers recommend not using non-POD structures because the layout may change between compilers (including same versions of compilers); so for example, character arrays are preferred over std::string.
It doesn't change the code to be C. It causes no C++ name mangling to be done - so you cannot overload functions exposed as extern "C" inside that block, for example, but the code is still C++.
You are just restricted from doing stuff that would not be callable from C (in the extern "C" block). You are exposing a C API but you can still use C++ behind the scenes. Just not in your extern "C" part of the interface.
This also means that you cannot export member functions (virtual or not) as extern "C" because C has no such thing.
Consider the following function defined in a C library:
void f(void (*callback)(int)) { callback(0); }
which will be called from a C++11 program defining the callback() as below:
struct S {
static void S::callback(int) noexcept {}
};
f(&S::callback);
Most compiler would probably compiler the above without any warnings, but, my question is, if strictly speaking, I must declare the callback as (a free) extern "C" function to be totally compliant with C++11 standard.
Specifications as extern "C" are for control of the names of functions, variables etc. But in your case S::callback address is passed as the argument in runtime, so the name of the function is not relevant, and no specification is necessary.
Does extern "C" do something more besides specifying an identifier should not be mangled?
Are C++ features available in functions that have been declared as extern "C"?
It only affects the name mangling so that the external visibility is clear to other applications.
extern "C" does not mean compile as C code. It means only that the function should be compiled so that it can be called from C code; what that actually affects is implementation-dependent. Anything you can do in C++ is fine inside such a function, including throwing exceptions.
You shouldn't throw exceptions from them, but otherwise you can implement the body of an extern "C" function with as many C++ features as you like.
This is perfectly fine:
MyObject myobj;
extern "C" {
int myfunc(char *c)
{ // c++ features used here
std::string s = myobj.method(....
}
}
In *.h header files of a C library, should one declare functions
extern void f();
// or only
void f();
when using only in C
when using from C++.
There's [almost] never any need to use the keyword extern when declaring a function, either in C or in C++. In C and in C++ all functions have external linkage by default. The strange habit of declaring functions in header files with extern probably has some historical roots, but it has been completely irrelevant for decades already.
There's one [obscure?] exception from the above in C, which is probably not directly related to what you are asking about: in C language (C99) if in some translation unit a function is defined as inline and also declared as extern (an explicit extern is used) then the inline definition of that function also serves as an external definition. If no declarations with explicit extern are present in the translation unit, then the inline definition is used as "internal" definition only.
P.S. There's such thing as extern "C" in C++, but that is a completely different matter.
In header files of a C library, should one declare functions:
extern void f();
// or only
void f();
Issue 1: Semantics
In a C++ program, the functions are declared as functions returning no value and taking no arguments.
In a C program, the functions are declared as functions returning no value and taking an indeterminate but not variable-length list of arguments.
To get the 'no arguments' meaning in C, use one of:
extern void f(void);
void f(void);
The same notation also means the same thing in C++, though for pure C++ code, using void in the argument list is not idiomatic (do not do it in pure C++ code).
Issue 2: Inter-working between C and C++
Tricky, but the normal rule would that you should declare the functions to C++ code as extern "C". To use the same source code for both, you then need to test the __cplusplus macro. You'd normally do something like:
#ifdef __cplusplus
#define EXTERN_C extern "C"
#define EXTERN_C_BEGIN extern "C" {
#define EXTERN_C_END }
#else
#define EXTERN_C /* Nothing */
#define EXTERN_C_BEGIN /* Nothing */
#define EXTERN_C_END /* Nothing */
#endif
EXTERN_C void f(void);
EXTERN_C_BEGIN
void f(void);
int g(int);
EXTERN_C_END
The options and variations are manifold, but the header can be used by both C and C++.
The macros would normally be defined in one general-purpose header that's used everywhere, and then the particular header would ensure that the general purpose header is included and then use the appropriate form of the macro.
Issue 3: Style
Formally, there is no need for the extern notation before a function declaration. However, I use it in headers to emphasize that it is a declaration of an externally defined function, and for symmetry with those (rare) occasions when there is a global variable declared in the header.
People can, and do, disagree over this; I go with the local rules ā but when I'm the rule-maker, the extern is included in a header.
For general use declare as
#ifdef __cplusplus
extern "C" {
#endif
void f(void);
#ifdef __cplusplus
}
#endif
Otherwise, extern is obsolete.
The latter is perfectly fine, since it's only a function definition, which tells those, who include this header: 'There's a function with this prototype somewhere around here'
In this context, functions differ clearly from variables, but that's a different matter.
Make sure though, that you do not include the function body, unless you declare it 'inline' or as part of a class definition (C++) or as a 'template function' (also C++).
Specifying extern in function prototype has no effect, since it is assumed by default. Whenever a compiler sees a prototype, it assumes a function is defined somewhere else (in the current or another translation unit). This holds for both of the languages.
The following thread has some useful comments in general about extern.
Effects of the extern keyword on C functions
I observed a function in a dll which has C linkage. This function returns class type. I am not sure how this is made possible as C doesn't understand class.
I wrote a sample dll and program myself and noted that the VC++ compiler shows a warning to this effect but doesn't stop you. The program is able to GetProcAddress of this function and call it to receive the returned object. The class definition was made available to program.
Furthermore, if I write a function with C linkage that returns a class type where this class is not even exported, the compiler doesn't issue any warning. The program can consume this function from the dll provided the class definition is made available to it.
Any thoughts on how this works? Is such a behavior compiler/platform specific?
You are misunderstanding the behavior of extern "C".
It only impacts the name of the function in the object file by preventing name mangling. It does not make a function neither "more C" or "less C++". The only additional limitation which extern "C" adds to a C++ function is that is shall not be overloaded.
It's possible for functions with C linkage to return objects that can't be expressed in C so long as they can be manipulated in C. According to my copy of Design & Evolution of C++ (section 11.3.3):
We considered several alternatives to the type-safe linkage schemes before deciding on the one actually added to the language [Stroustrup,1988]: ...
provide type-safe linkage only for functions that couldn't be C functions because they had types that couldn't be expressed in C. ...
A function declared to have C linkage still has C++ calling semantics. That is, the formal arguments must be declared, and the actual arguments must match under the C++ matching and ambiguity control rules. ... Had we provided special services for C, we would have been obliged to add an unbounded set of language calling conventions to C++ compilers [for linking to Pascal, Fortran, PL/I, etc.]. ...
Linkage, inter-language calls, and inter-language object passing are inherently difficult problems and have many implementation-dependent aspects. ... I expect we haven't heard the last of this matter.
That is, C++ linkage isn't based on whether the types involved are valid C types. That is an intentional design decision. It allows you to create a DLL compiled in C++ but that can be used from C via a header:
// in the header
struct Foo; // forward declaration
#ifdef __cplusplus
extern "C" {
#endif
struct Foo* create_foo();
void destroy_foo(struct Foo*);
void foo_bar(struct Foo*);
#ifdef __cplusplus
} // extern "C"
// now declare Foo
struct Foo {
void bar();
};
#endif
// in the implementation file
#include <iostream>
extern "C" {
Foo* create_foo()
{
return new Foo();
}
void destroy_foo(Foo* f)
{
delete f;
}
void foo_bar(Foo* f)
{
f->bar();
}
}
void Foo::bar()
{
std::cout << "Foo::bar() called\n";
}
Note the calls to new, delete and std::cout. These all require the C++ runtime. Therefore, the implementation file must be compiled with C++, but since the functions have C linkage, the header can be used from either C or C++.
So how do you get a Foo in C? In this case, you don't, because there's no way to fully declare it in the header in a way that C will understand. Instead, C only sees the forward declaration, which creates an incomplete type. C doesn't know how large an incomplete type is, so C functions can't create it or operate on them directly, but C does know how large a pointer to an incomplete type is, so C can operate on a pointer to an incomplete type. You can get much more creative and actually create POD types in C++ that you can operate on directly in C.
As long as you only use Foo*s in C, you don't have to actually define the Foo struct in C. It so happens that APR uses a similar design ("Creating an APR Type," I couldn't find a better link).
A class object is basically just a struct object, with some extra "hidden" members for the vtbl and so on.
However, I'm not sure what you mean by "the program can consume this function provided the class definition is made available to it". C would throw a compiler error on seeing class Blah { ... };.