GCC: linker error when working with old C code - c++

I'm running into a mysterious situation with the GCC compiler. So I've got the following files:
//main.cpp
#include "mleak_cpp.h"
int main(int argc, char* argv[])
{
foo();
__memory_malloc(10,"hello",5);
return 0;
}
//mleak_cpp.h
......
void foo(void);
void* __memory_malloc(size_t size, const char* file, int line);
//mleak_cpp.cpp
//definitions of the functions;
void foo(void){printf("foo\n");
void* __memory_malloc(size_t size, const char* file, int line){
printf("%s,%d\n",file,line);
InitDoubleLinkList();
void* p = malloc(size);
if(p == NULL)
return NULL;
__DuLinkList* pListNode;
pListNode = (__DuLinkList*)malloc(sizeof(__DuLinkList));
pListNode->address = p;
pListNode->memorysize = size;
pListNode->file = file;
pListNode->line = line;
InsertBlockToList(pListNode);
return p;
}
For some reason, the call to void foo(void) is fine, but the call to "__memory_malloc" goes down with a linker error, "undefined reference" blah blah. What's the difference between the two functions that causes the different behaviour?
I tried adding "extern C" to the "#include" directive, so main.cpp reads:
extern "C"{
#include "mleak_cpp.h"
}
and adding the keyword "extern" before the declarations of the functions, and this time the call to "foo()" fails too with the same error.
I appreciate any help from you guys

You're placing extern "C" in the wrong place.
If main.c is truly a C file, and mleak_cpp.cpp is truly a C++ function, then you need to put an extern "C" ahead of the definition of __memory_malloc() like so:
extern "C" void* __memory_malloc(size_t size, const char* file, int line){
// ...
}
If you put extern "C" in the mleak_cpp.h file, it needs to be guarded:
#ifdef __cplusplus
extern "C" {
#endif
/* ... body of header ... */
#ifdef __cplusplus
}
#endif
Also, it's not clear why foo works in your example above, when one file calls __foo() but the other file defines foo(). I assume something more is at play, such as an editing error in your question.

extern "C" is for C++, not C, and tells it that the function's name shouldn't be mangled. In C code, you should never see this. Generally, you put it in header files, and you guard it, like this:
#ifdef __cplusplus
extern "C" {
#endif
/* C and C++ compatible header file body here */
#ifdef __cplusplus
} /* end extern "C" */
#endif
If you do it this way though, you need to include the header file in both your C and C++ files, so that the C++ compiler knows to use C linkage.
You can put the extern "C" in front of the function definition in C++ instead and leave it out of the header, but this only works if you only include the headers in C code, so it's recommended to do it the way I pointed out above.

Related

Xcode c/c++ undefined symbols

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.

error: expected unqualified-id on extern "C"

I have a cpp code in which I want to call a c function.
Both compile well to .o files, but when the clang++ is executing for compilation, I receive the following error:
file.cpp:74:12: error: expected unqualified-id
extern "C"
^
The code in the cpp file is the following:
void parseExtern(QString str)
{
#ifdef __cplusplus
extern "C"
{
#endif
function_in_C(str);
#ifdef __cplusplus
}
#endif
}
How can I avoid the error ? I can't compile the c file with clang++, I really need to use extern. Thanks.
The extern "C" linkage specification is something you attach to a function declaration. You don't put it at the call site.
In your case, you'd put the following in a header file:
#ifdef __cplusplus
extern "C"
{
#endif
void function_in_C(char const *); /* insert correct prototype */
/* add other C function prototypes here if needed */
#ifdef __cplusplus
}
#endif
Then in your C++ code, you just call it like any other function. No extra decoration required.
char const * data = ...;
function_in_C(data);

Export duplicated functions in two namespaces (C++)

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.

Using a mixed C/C++ header to use C++ object in C

I have been following this guide on how to call a member function of a C++ object from C. As I've understood it, the C code should interpret the class as a struct of the same name, and whenever it wants to call a function through an object of this class it should use an intermediate callback function. The header looks like this:
// CInterface.h
#ifdef __cplusplus
...
class CInterface
{
public:
...
void OnMessage(U8* bytes); // I want to call this function from C.
private:
...
};
#else
typedef
struct CInterface
CInterface;
#endif
#ifdef __cplusplus
extern "C" {
#endif
#if defined(__STDC__) || defined(__cplusplus)
//extern void c_function(CInterface*); /* ANSI C prototypes (shouldn't be needed) */
extern CInterface* cpp_callback_function(CInterface* self, unsigned char * bytes);
#else
//extern void c_function(); /* K&R style (shouldn't be needed) */
extern CInterface* cpp_callback_function(unsigned char * bytes);
#endif
#ifdef __cplusplus
}
#endif
The C code that fails right now looks like this:
// main.c
#include "CInterface.h"
int main(int argc, char* argv[])
{
void* ptr;
int *i = ptr; // Code that only compiles with a C compiler
CInterface cinterface; // This should declare a struct
}
The error is: error C2079: 'cinterface' uses undefined struct 'CInterface'.
It sounds like the header is being read as c++ code as the struct is not defined, but main.c is being compiled by C according to Visual Studio (I also double checked this by adding some C-specific code). However, if I add parentheses like this:
CInterface cinterface();
the code compiles which makes no sense to me as it now is an object which shouldn't work in C.
The callback function is implemented in a third file, CInterface.cpp, which acts as the "intermediate".
So the question is how I solve this error message, or if I got the entire approach wrong. It's the first time I mix C/C++ code and I'm relatively new to both languages.
In your example CInterface is only defined for C++. If you take a closer look at the example you linked you'll notice that this is also the case for the Fred class.
From C you can only pass around pointers to CInterface and you have to rely on C++ functions defined with C linkage to actually manipulate CInterface instances.
Otherwise you could define a struct as a means to pass around data between C and C++. Just ensure its definition is declared as extern "C" when used from C++:
#ifdef __cplusplus
extern "C" {
#endif
struct CandCPlusPlus {
// ...
};
#ifdef __cplusplus
}
#endif

How to call a c++ class and its method from a c file

I am trying to access a C++ class and call its method from a .c file.
I google this topic and find this http://developers.sun.com/solaris/articles/mixing.html
It says:
You can write extern "C" functions in C++ that access class M objects and call them from C code.
Here is a C++ function designed to call the member function foo:
extern "C" int call_M_foo(M* m, int i) { return m->foo(i); }
My question is where do I put the about line? In my C++ .h file? Or C .h file?
And it goes on and says:
Here is an example of C code that uses class M:
struct M; // you can supply only an incomplete declaration
int call_M_foo(struct M*, int); // declare the wrapper function
int f(struct M* p, int j) // now you can call M::foo
{
return call_M_foo(p, j);
}
But how/where do I create the class M in my C file?
And where do I put the above code? C .h file? C++ .h file? Or C .c file?
Thank you.
Thank you for GMan's detailed answer.
I did follow your suggestion. But I get compile error in my .c file.
main.c:33:
./some_class.h:24: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘attribute’ before ‘’ token
./some_class.h:25: error: expected ‘)’ before ‘’ token
./some_class.h:26: error: expected ‘)’ before ‘*’ token
And here are my some_class.h line 24-26:
#ifdef __cplusplus
class M {
public:
M();
virtual ~M();
void method1(char* name, char* msg);
};
extern "C" {
#else
struct M;
#endif
/* access functions line 24-26 are here*/
M* M_new(void);
void M_delete(M*);
void M_method1(M*, char*, char*);
#ifdef __cplusplus
}
#endif
For some reason, my C compiler does not like extern "C" in GMan's original some_test.h. So I have to modify to above. It seems like the C compiler does not like/understand the struct M; line.
Any idea will be much appreciated.
Your header file, which is shared between your C and C++ code:
#ifdef __cplusplus // only actually define the class if this is C++
class some_class
{
public:
int some_method(float);
};
#else
// C doesn't know about classes, just say it's a struct
typedef struct some_class some_class;
#endif
// access functions
#ifdef __cplusplus
#define EXPORT_C extern "C"
#else
#define EXPORT_C
#endif
EXPORT_C some_class* some_class_new(void);
EXPORT_C void some_class_delete(some_class*);
EXPORT_C int some_class_some_method(some_class*, float);
Then your source file:
#include "some_foo.h"
int some_class::some_method(float f)
{
return static_cast<int>(f);
}
// access functions
EXPORT_C some_class* some_class_new(void)
{
return new some_class();
}
EXPORT_C void some_class_delete(some_class* this)
{
delete this;
}
EXPORT_C int some_class_some_method(some_class* this, float f)
{
return this->some_method(f);
}
Now compile that source, and link to it. Your C source would be something like:
#include "some_class.h"
some_class* myInstance = some_class_new();
int i = some_class_some_method(myInstance, 10.0f);
some_class_delete(myInstance);
If you're serious about mixing C and C++, you'll want macro's.
Here are some sample macro's that would make this much easier:
// in something like c_export.h
// extern "C" macro
#ifdef __cplusplus
#define EXPORT_C extern "C"
#else
#define EXPORT_C
#endif
// new
#define EXPORT_C_CLASS_NEW(classname) EXPORT_C \
classname * classname##_new(void)
#define EXPORT_C_CLASS_NEW_DEFINE(classname) \
EXPORT_C_CLASS_NEW(classname) \
{ return new classname (); }
// repeat as much as you want. allows passing parameters to the constructor
#define EXPORT_C_CLASS_NEW_1(classname, param1) EXPORT_C \
classname * classname##_new( param1 p1)
#define EXPORT_C_CLASS_NEW_1_DEFINE(classname, param1) \
EXPORT_C_CLASS_NEW_1(classname, param1) \
{ return new classname (p1); }
// delete
#define EXPORT_C_CLASS_DELETE(classname) EXPORT_C \
void classname##_delete( classname * this)
#define EXPORT_C_CLASS_DELETE_DEFINE(classname) \
EXPORT_C_CLASS_DELETE(classname) \
{ delete this; }
// functions
#define EXPORT_C_CLASS_METHOD(classname, methodname, ret) EXPORT_C \
ret classname##_##methodname##( classname * this)
#define EXPORT_C_CLASS_METHOD_DEFINE(classname, methodname, ret) \
EXPORT_C_CLASS_METHOD(classname, methodname, ret) \
{ return this->##methodname##(); }
// and repeat as necessary.
#define EXPORT_C_CLASS_METHOD_1(classname, methodname, ret, param1) EXPORT_C \
ret classname##_##methodname( classname * this, param1 p1)
#define EXPORT_C_CLASS_METHOD_1_DEFINE(classname, methodname, ret, param1) \
EXPORT_C_CLASS_METHOD_1(classname, methodname, ret, param1) \
{ return this->##methodname##(p1); }
And so on. Our header/source becomes:
// header
#include "c_export.h" // utility macros
#ifdef __cplusplus // only actually define the class if this is C++
class some_class
{
public:
int some_method(float);
};
#else
// C doesn't know about classes, just say it's a struct
typedef struct some_class some_class;
#endif
// access functions
EXPORT_C_CLASS_NEW(some_class);
EXPORT_C_CLASS_DELETE(some_class);
EXPORT_C_CLASS_METHOD_1(some_class, some_method, int, float);
// source
#include "some_foo.h"
int some_class::some_method(float f)
{
return static_cast<int>(f);
}
// access functions
EXPORT_C_CLASS_NEW_DEFINE(some_class);
EXPORT_C_CLASS_DELETE_DEFINE(some_class);
EXPORT_C_CLASS_METHOD_1_DEFINE(some_class, some_method, int, float);
And that's much more concise. It could be made simpler (possibly) with variadic macro's, but that's non-standard and I leave that to you. :] Also, you can make macro's for normal non-member functions.
Note that C does not know what references are. If you want to bind to a reference, your best bet is probably just to write the export definition manually. (But I'll think about it, maybe we can get it automatically).
Imagine our some_class took the float by (non-const)reference (for whatever reason). We'd define the function like so:
// header
// pass by pointer! v
EXPORT_C_CLASS_METHOD_1(some_class, some_method, int, float*) ;
// source
EXPORT_C_CLASS_METHOD_1(some_class, some_method, int, float*)
{
// dereference pointer; now can be used as reference
return this->some_method(*p1);
}
And there we go. C would interface with references with pointers instead:
// c source, if some_method took a reference:
float f = 10.0f;
int i = some_class_some_method(myInstance, &f);
And we pass f "by reference".
You need to split it among the C++ header and implementation files.
foo.h:
extern "C" int call_M_foo(M* m, int i);
foo.cc:
extern "C" int call_M_foo(M* m, int i) {
return m->foo(i);
}
To create the object of type M, you would need a similar function:
foo.h:
struct M;
extern "C" M* create_M();
foo.cc:
extern "C" M* create_M() {
return new M;
}
You have several questions combined here so I will answer them individually.
My question is where do I put the about line? In my c++ .h file? or c .h file?
The extern "C" line goes in the C++ file. It essentially tells the compiler to
limit everything whithin the extern "C" block to the C subset of C++, and to
export functions declared in this area accordingly.
But how/where do I create the class M in my c file?
You can't. C does not have the concept of classes, and there's absolutely no
way to instantiate a class directly. You essentially have to export a C function
in your C++ file which creates the class and returns it as a pointer. Then you
can pass that pointer around your C application. You can't actually modify the
class directly in your C application, because C does not support classes, and
your C++ compiler may insert "hidden" variables for bookkeeping inside the
actual declaration of the class.
And where do I put the above code?
The piece of code that uses a structure pointer goes in the C file. You are
forced to use a structure pointer because C does not support classes at all.
You can put function calls using that function anywhere in a C implementation
file, just like normal C function calls.
All the information you need is in the link you provide. You just need to understand that there needs to be a strict separation between C and C++ code.
C++ code can call any C code.
C code usually cannot call any C++ code.
C functions can be implemented by C++ code.
The key part to understand is that the C and C++ compilers mangle function names when making object files in different ways, so they would normally not be able to interoperate (at link time), except that C++ can be prompted to know the difference by using extern "C"
The prototype:
void f(int); might be mangled by a C compiler to: _f, but a C++ compiler might choose a very different name eg f_int, and so the linker would not know they are supposed to be the same.
However:
extern "C" void f(int);
would be mangled by a C++ compiler to _f, but a C compiler would choke on the extern "C". To avoid this you should used something like this:
#ifdef __cplusplus
extern "C" {
#endif
void f(int);
#ifdef __cplusplus
} /* closing brace for extern "C" */
#endif
Now the whole of the above section can live in a .h file and is, as the sun.com article states, a mixed-language header.
This means that a .c or .cpp file can #include this header and code can call f();
and either a .c or .cpp file can #include this header and implement it:
void f()
{
}
Now the good bit is that a .cpp file can implement this to call any C++ code it likes.
Now to answer your specific questions:
The first code sample can only go in a .cpp file.
The second code sample can only go in a .c file.
Additionally class M must be declared and defined in C++ files only.
The site you have linked to has the answer already:
You can declare function print in a
header file that is shared by C and
C++ code:
#ifdef __cplusplus extern "C"
#endif int print(int i, double d);
You can declare at most one function
of an overloaded set as extern "C"
Here is the example C header for the
wrapper functions:
int g_int(int);
double g_double(double);
Basically, there can be a header shared between the two that declares the function prototype, adding the extern "C" modifier if you are in C++ to ensure the function can be accessed in an object from C. You define the body of the function later on in the C++ code as usual, if necessary inside a class etc, and you use the function in C like normal.