I am trying to call an inline function defined in C from C++ code and I am getting an unresolved symbol error. Can I even do this?
In def.h:
#ifdef __cplusplus
extern "C" {
#endif
#include "types.h"
extern inline void foo();
#ifdef __cplusplus
}
#endif /* extern "C" */
In def.c:
inline void foo()
{
some code
}
Elsewhere in c++ code:
void bar()
{
foo();
}
And this is where I get an unresolved symbol error. Is there a way to make this compile? And if so, how will it work? Will the compiler replace the function call in my C++ code by the C definition? Eliminating functional calls is important as this is for an embedded environment.
Thank you.
Most compilers generate code on source file level; to generate code, the compiler must "see" the source of all functions for which it needs to generate code. Unless you have LTO/LTGC, you have to make the source of all inline functions available in every file where they are called.
Try moving the source of the inlined function(s) into the corresponding header:
def.h:
#ifdef __cplusplus
extern "C" {
#endif
#include "types.h"
inline void foo()
{
some code
}
#ifdef __cplusplus
}
#endif /* extern "C" */
def.c:
Remove foo() definition from this file (or remove this file).
Elsewhere in c++ code:
#include "def.h"
void bar()
{
foo();
}
The definition of the inlined C function should go into a header visible and included by your C++ code.
Related
I have an inline function, roughly like this:
inline void SomeFunction() {
extern void SomeOtherFunction();
SomeOtherFunction();
}
This is a simplification: my functions do have parameters and return values.
However, I want this header to work in both C and C++ files. Currently, linking fails because C++ files attempt to find an implementation of SomeOtherFunction with C++ linkage. I thought I could just fix this by using extern "C":
inline void SomeFunction() {
#ifdef __cplusplus
extern "C" void SomeOtherFunction();
#else
extern void SomeOtherFunction();
#endif
SomeOtherFunction();
}
This causes Clang to fail with:
error: expected unqualified-id
extern "C" void SomeOtherFunction();
^
How can I do this correctly?
extern "C" is a linkage-specification. C++ standard section 7.5 Linkage specifications paragraph 4 states that:
A linkage-specification shall occur only in namespace scope (3.3).
E.g. you can say extern "C" in global namespace or some specific namespace. Outside of namespaces it is illegal.
Function declarations are possible though in smaller scopes. If you remove linkage specification your code will compile (but not link):
inline void SomeFunction() {
extern void SomeOtherFunction();
SomeOtherFunction();
}
If you really need SomeOtherFunction declaration in a smaller scope (e.g. hide from global scope) you can put your declaration into a header file to a dedicated scope and then use in your function:
Header:
namespace other {
extern "C" void SomeOtherFunction();
}//namespace other
Code:
void SomeFunction()
{
other::SomeOtherFunction();
}
Credit goes to these two answers on stackoverflow: here and here.
From the C++11 standard (in [dcl.link], emphasis mine):
4 Linkage specifications nest. When linkage specifications nest, the innermost one determines the language linkage. A linkage specification does not establish a scope. A linkage-specification shall occur only in namespace scope.
(linkage-specification refers to extern string-literal ..., i.e. extern "C" in your case.)
This means you can't have extern "C" inside of a class or function.
What's the point of declaring SomeOtherFunction inside of SomeFunction? It still has to be a global symbol and visible to the linker.
So why not do this?
#ifdef __cplusplus
extern "C"
#endif
void SomeOtherFunction();
inline void SomeFunction() {
SomeOtherFunction();
}
The following also seems to work:
extern "C" {
inline void SomeFunction() {
extern void SomeOtherFunction();
SomeOtherFunction();
}
}
But it would have the side effect of making SomeFunction also use C linkage (which is hopefully OK as (per your requirements) it needs to be usable from C, too).
You can do this like that. I assume you have a header file, a C source and a C++ source.
Header file:
inline void SomeFunction()
{
void SomeOtherFunction_Bridge();
SomeOtherFunction_Bridge();
}
C++ source:
extern "C"
{
void SomeOtherFunction();
}
void SomeOtherFunction_Bridge()
{
SomeOtherFunction();
}
C source:
void SomeOtherFunction()
{
// Function with a code doing something
}
void SomeOtherFunction_Bridge()
{
SomeOtherFunction();
}
Checked on GCC, it compiles.
extern tells the compiler that a symbol (function, variable) is defined in some other module. When this module (C++ file) is compiled, object file contains a list of external symbols it needs. So this is on a level of a C++ file, it cannot be in smaller scope (function, block).
I have a .cpp file which I declare a function
#ifndef MyFile_hpp
#define MyFile_hpp
#ifdef __cplusplus
extern "C" {
#endif
void runCode();
#ifdef __cplusplus
}
#endif
#endif
This works fine. I can call this function within my Objc. In my implementation I have an extern void that it will not let me call. It's giving the undefined symbols. I need this to build as is, the extern will be declared in a different file upon compiling. Having the extern, should this compiler just trust me and let me build?
#include "MyFile.h"
extern int runMe();
#ifdef __cplusplus
extern "C" {
#endif
void runCode() {
runMe();
}
#ifdef __cplusplus
}
#endif
I think what you are doing is probably correct.
The compiler doesn't just trust you. A C++ function is declared to the linker using additional characters, or "decorations" that define the full detail of the cclass it is a member of and all its arguments. A C function has none of that, just the raw name, so it is easy for the linker to tell the difference.
How should I call a C++ function (no classes involved) from a Swift file?
I tried this:
In someCFunction.c:
void someCFunction() {
printf("Inside the C function\n");
}
void aWrapper() {
someCplusplusFunction();
}
In someCpluplusfunction.cpp:
void someCplusplusFunction() {
printf("Inside the C++ function");
}
In main.swift:
someCFunction();
aWrapper();
In Bridging-Header.h:
#import "someCFunction.h"
#import "someCplusplusFunction.h"
I found this answer very informative, but still I cannot make it work.
Could you point me in the right direction?
Thanks!
What does the header look like?
If you want to explicitly set the linking type for C-compatible functions in C++, you need to tell the C++ compiler so:
// cHeader.h
extern "C" {
void someCplusplusFunction();
void someCFunction();
void aWrapper();
}
Note that this isn't valid C code, so you'd need to wrap the extern "C" declarations in preprocessor macros.
On OS X and iOS, you can use __BEGIN_DECLS and __END_DECLS around code you want linked as C code when compiling C++ sources, and you don't need to worry about using other preprocessor trickery for it to be valid C code.
As such, it would look like:
// cHeader.h
__BEGIN_DECLS
void someCplusplusFunction();
void someCFunction();
void aWrapper();
__END_DECLS
EDIT: As ephemer mentioned, you can use the following preprocessor macros:
// cHeader.h
#ifdef __cplusplus
extern "C" {
#endif
void someCplusplusFunction();
void someCFunction();
void aWrapper();
#ifdef __cplusplus
}
#endif
I have these two namespaces, each one containing a function with the same name, like
namespace group1 {
void add(int arg) {
}
}
namespace group2 {
void add(bool arg) {
}
}
and I specify this in the header with the declarations
#ifdef __cplusplus
extern "C" {
#endif
// My namespaces and functions prototypes here
#ifdef __cplusplus
}
#endif
and I am trying to export them into a DLL, with GCC. I get a warning about a conflict between them because they have the same name, then an error at linking time. I thought the name was mangled in the object file based on the arguments, too. I don't know if the linker cares about the namespace too. How could I make this work? Thanks.
If these are C++ functions, you have to remove the extern "C" bracketing:
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
}
#endif
extern "C" tells the compiler "don't mangle this name"--but (as you say) you want the mangling.
You can't really do that directly. When you use the extern "C", you are declaring that the functions are exported as if they were C functions, not C++.
This means (among other things)
Namespaces are removed, and are not considered part of the name
No name mangling due to arguments is done
The best you can do is create extern "C" functions which redirect.
#ifdef __cplusplus
extern "C" {
#endif
void group1_add(int arg);
void group2_add(bool arg);
#ifdef __cplusplus
}
#endif
And the implementations of the wrapper functions would then use either group1::add() or group2::add() as appropriate.
I need to call a C++ member function from a C program.
I created .cpp/.h wrapper files in the C code, wrapping the C++ member functions.
i.e.- wrapper.cpp
#include "wrapper.h"
extern "C" {
void wrap_member1()
{
Class::member1();
}
void wrap_member2()
{
Class::member2();
}
}
and wrapper.h:
#include <windows.h>
#include <stdio.h>
#include "../C++ class with members I need to call.h"
extern "C" void wrap_member1();
extern "C" void wrap_member2();
My problem is when I complie:
error C2061: syntax error : identifier 'Class'
It points to the .h declaration of the C++ class as an error. Same result as if I did not have the wrapper files....?
P.S. I also removed the "extern "C" " from the prototypes and received an error on the wrapper function:
error C2732: linkage specification contradicts earlier specification for 'wrap_member1'
Any advice?
There are two issues:
One, you are including a C++ header file in a C header file. This means the C compiler gets C++ code. This is what causes the error you are experiencing. As Reed Copsey suggests, put the #include in the C++ source file instead of the C header file.
Two, you are using extern "C" in the C header file. Wrap your statement in an #ifdef as such:
#ifdef __cplusplus
extern "C" {
#endif
/* Functions to export to C namespace */
#ifdef __cplusplus
}
#endif
This will allow the file to be usable for both C and C++.
In your wrapper you must conditionaly compile the extern "C" part, because is a C++ only construct:
wrapper.h:
#ifdef __cplusplus
extern "C" {
#endif
extern void wrap_member1();
#ifdef __cplusplus
}
#endif
In the wrapper.cpp:
extern "C" void wrap_member1()
{
Class::Member1();
}
In your C module you include only wrapper.h and link to wrapper.obj.
BTW Objective-C is capable of consuming C++, just change the name of your file from *.m to *.mm in XCode.
You need to include your class in wrapper.cpp:
#include "wrapper.h"
#include "ClassHeaderFile.h" // The header that defines "Class"
extern "C" {
void wrap_member1()
{
Class::member1();
}
void wrap_member2()
{
Class::member2();
}
}