Limitations to functions declared as `extern "C"`? C++ features still usable? - c++

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(....
}
}

Related

Is there any difference, whether a struct declared in the 'extern "C"' block or not?

Let's say, I have the header file:
#ifdef __cplusplus
extern "C" {
#endif
struct S
{
int i;
double d;
// etc
};
// Or start the 'extern "C"' block here?..
void f(A* a);
#ifdef __cplusplus
}
#endif
It should be used by C/C++ sources.
My question is: if I carry the struct A declaration out of the extern "C", whether this code will be compatible with a library which was built with the struct A declared as extern "C"?
That is, we built a library with the header as it is presented above, then we moved the extern "C" to the position marked by the corresponding comment line and, finally, we are trying to build a C++ application using the resulting header.
If all of this will be successful? In other words, if the extern "C" influence on a struct declaration?
Whether it depends what language (C/C++) the library is written on?
extern by itself declares external linkage, which is a default state for C++ functions.
Specification "C" gives C language linkage.
Only function names and variable names with external linkage have a language linkage, classes and class members are not affected. struct declaration is a class. If that file meant to be used with C code, there might be problem that older C standard do not support declaration in that format.
Specification "C" makes name conventions of externally linked entities compatible with said language, even while compatibility is implementation-dependent. E.g. for gcc your function would have C++ mangled name _Z3fooP1A, but with C it might be just _foo.

Why we should Extern "C" a struct? [duplicate]

I'm writing a C++ shared library for a C program to use. However, I have a question about extern and extern "C".
Consider the following code
My header file is like this:
#ifdef __cplusplus
extern "C" int global;
extern "C" int addnumbers(int a, int b);
#else
extern int global;
#endif
This works perfectly fine; I just have to declare
int global;
in either my .cpp or my .c file. However, what I don't understand is:
What is the difference between extern "C" and extern here? I tried commenting out extern "C" int global and it works! Why?
I know that extern "C" is used for making C linkage. That's why I have extern "C" int addnumbers(int,int). In other words, if I want to write a C++ function that is to be used in a C program, I write extern "C". Now, what about global variables - the situation is different here I guess? I want the C program to use a C++ variable named global, but I can use extern not extern "C". Why is that? This is not intuitive to me.
Comment: I don't think this is a duplicate, because I'm asking what the difference is when you use it for variables versus functions.
By attaching extern "C" to your C++ declarations (objects and functions alike) you give them "C linkage" - make them accessible from C code. If you omit this "language linkage" specification, the compiler doesn't do any effort to do proper linkage. In the case of functions, this results in failed linkage, because of mangling. In the case of global variables, everything might work fine, because variables don't need mangling.
However, on my system (MS Visual Studio), linkage between C and C++ doesn't work if I "forget" to specify the extern "C" linkage specification in the C++ header file. Example error message:
error LNK2001: unresolved external symbol "int global" (?_global)
While, when I examine a compiled C++ source code that contains the definition of global with the dumpbin utility, I see
00B 00000014 SECT4 notype External | ?global##3HA (int global)
So MS Visual Studio mangles the names of global variables, unless they have C linkage - this makes C linkage specifications mandatory.
In addition, consider the following example:
namespace example {
int global;
}
If the global variable is inside a namespace, C code will not get access to it. In this case, all compilers will require the proper linkage specification on the C++ declaration:
namespace example {
extern "C" int global;
}
Conclusion:
Use extern "C" when you want C linkage - doesn't matter if it's a function or a global variable. If it's a global variable, it may work regardless, but it's not guaranteed (and may be dangerous).
extern simply tells the compiler that the next variable(global) may not have been declared yet, but it is declared as global in a different translation unit, and during the linking stage the symbol "global" will be associated with an area in the memory.
while extern "C" is, as a few people commented, is used to solve the issue of name mangling in C++, this function will be known as addnumbers_i_i (or something similar) by the linker, while in c its symbol is addnumbers
"C++ has a special keyword to declare a function with C bindings: extern "C". A function declared as extern "C" uses the function name as symbol name, just as a C function. For that reason, only non-member functions can be declared as extern "C", and they cannot be overloaded."
There is no standard in C++ for function names generated by compiler. Keyword extern "C" instructs compiler to generate function name in C standard.
I find that extern "C" is used to make the C++ function compiled in C standard and it don't do with variables, for the solutions of function name in C and C++ are different. Such as "void foo( int x, int y )", C compiler will translate it into "_foo", while C++ compiler will translate it into "_foo_int_int".

extern "C" with class and DLL

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.

extern and extern "C" for variables

I'm writing a C++ shared library for a C program to use. However, I have a question about extern and extern "C".
Consider the following code
My header file is like this:
#ifdef __cplusplus
extern "C" int global;
extern "C" int addnumbers(int a, int b);
#else
extern int global;
#endif
This works perfectly fine; I just have to declare
int global;
in either my .cpp or my .c file. However, what I don't understand is:
What is the difference between extern "C" and extern here? I tried commenting out extern "C" int global and it works! Why?
I know that extern "C" is used for making C linkage. That's why I have extern "C" int addnumbers(int,int). In other words, if I want to write a C++ function that is to be used in a C program, I write extern "C". Now, what about global variables - the situation is different here I guess? I want the C program to use a C++ variable named global, but I can use extern not extern "C". Why is that? This is not intuitive to me.
Comment: I don't think this is a duplicate, because I'm asking what the difference is when you use it for variables versus functions.
By attaching extern "C" to your C++ declarations (objects and functions alike) you give them "C linkage" - make them accessible from C code. If you omit this "language linkage" specification, the compiler doesn't do any effort to do proper linkage. In the case of functions, this results in failed linkage, because of mangling. In the case of global variables, everything might work fine, because variables don't need mangling.
However, on my system (MS Visual Studio), linkage between C and C++ doesn't work if I "forget" to specify the extern "C" linkage specification in the C++ header file. Example error message:
error LNK2001: unresolved external symbol "int global" (?_global)
While, when I examine a compiled C++ source code that contains the definition of global with the dumpbin utility, I see
00B 00000014 SECT4 notype External | ?global##3HA (int global)
So MS Visual Studio mangles the names of global variables, unless they have C linkage - this makes C linkage specifications mandatory.
In addition, consider the following example:
namespace example {
int global;
}
If the global variable is inside a namespace, C code will not get access to it. In this case, all compilers will require the proper linkage specification on the C++ declaration:
namespace example {
extern "C" int global;
}
Conclusion:
Use extern "C" when you want C linkage - doesn't matter if it's a function or a global variable. If it's a global variable, it may work regardless, but it's not guaranteed (and may be dangerous).
extern simply tells the compiler that the next variable(global) may not have been declared yet, but it is declared as global in a different translation unit, and during the linking stage the symbol "global" will be associated with an area in the memory.
while extern "C" is, as a few people commented, is used to solve the issue of name mangling in C++, this function will be known as addnumbers_i_i (or something similar) by the linker, while in c its symbol is addnumbers
"C++ has a special keyword to declare a function with C bindings: extern "C". A function declared as extern "C" uses the function name as symbol name, just as a C function. For that reason, only non-member functions can be declared as extern "C", and they cannot be overloaded."
There is no standard in C++ for function names generated by compiler. Keyword extern "C" instructs compiler to generate function name in C standard.
I find that extern "C" is used to make the C++ function compiled in C standard and it don't do with variables, for the solutions of function name in C and C++ are different. Such as "void foo( int x, int y )", C compiler will translate it into "_foo", while C++ compiler will translate it into "_foo_int_int".

Can C++ functions marked as Extern "C" throw?

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? :))