Is there anything special I need to do in order to mix object filescreated by the C and the C++ comp

R

Ramon F Herrera

I created one *.o file from a C source, using gcc

I created another *.o file from a C++ source, using g++.

The linking pass is failing.

Should I use gcc, g++ or ld for linking? I am guessing the latter.

Are there any special flags, steps or gotchas?

TIA,

-Ramon
 
R

Ramon F Herrera

I created one *.o file from a C source, using gcc

I created another *.o file from a C++ source, using g++.

The linking pass is failing.

Should I use gcc, g++ or ld for linking? I am guessing the latter.

Are there any special flags, steps or gotchas?

TIA,

-Ramon


If it matters, the C++ program is the main one, and it makes a call to
a function in the C program.

-RFH
 
J

Joshua Maurice

I created one *.o file from a C source, using gcc

I created another *.o file from a C++ source, using g++.

The linking pass is failing.

Should I use gcc, g++ or ld for linking? I am guessing the latter.

Are there any special flags, steps or gotchas?

What exactly is failing?

Possibly your problem: A C++ function is not a C function. They look
different to the linker.

//AA.c
int foo() { return 1; }

//BB.cpp
int foo();
int main() { return foo(); }

When these two source files are given to gcc, for example, they will
both compile fine, but you will get an unresolved symbol error when
you try to link it into an executable. The "int foo();" in the C++
source file defines a C++ function, which has a different kind of
linkage than a C function. The linker will treat them as two different
functions.

//CC.c
int foo() { return 1; }

//DD.cpp
extern "C" int foo();
int main() { return foo(); }

When you try to compile and link CC and DD, it should link
successfully. The
extern "C"
tells the C++ compiler to use C rules for linkage, and then the linker
will see that the foo's "are the same" and do what you want.
 
R

Ramon F Herrera

What exactly is failing?

Possibly your problem: A C++ function is not a C function. They look
different to the linker.

//AA.c
int foo() { return 1; }

//BB.cpp
int foo();
int main() { return foo(); }

When these two source files are given to gcc, for example, they will
both compile fine, but you will get an unresolved symbol error when
you try to link it into an executable. The "int foo();" in the C++
source file defines a C++ function, which has a different kind of
linkage than a C function. The linker will treat them as two different
functions.

//CC.c
int foo() { return 1; }

//DD.cpp
extern "C" int foo();
int main() { return foo(); }

When you try to compile and link CC and DD, it should link
successfully. The
    extern "C"
tells the C++ compiler to use C rules for linkage, and then the linker
will see that the foo's "are the same" and do what you want.


The problem was fixed by the extern "C" statement, Josh.

How about the opposite, how should I refer to to an extern C++
function?

Let me guess:

extern "C++"

-Ramon
 
P

Pascal J. Bourguignon

Ramon F Herrera said:
The problem was fixed by the extern "C" statement, Josh.

Notice that you can wrap several declarations in a block:

extern "C"{
#include <c_code.h>
int foo(int);
}

How about the opposite, how should I refer to to an extern C++
function?

Let me guess:

extern "C++"

If that was that easy!

Since a lot of C code can be compiled by C++ compilers, the easiest is
to consider the C code as C++ code, and just call the other C++
functions without further ado.

However, if you have non-C++ conciscous C code, you might have to
review it and modify it slightly to avoid the things that are excluded
by C++. For example you cannot use the identifier 'new' in C++ code
since it's a keyword, so any C code that would it would have to be
edited. There are a number of similar gotchas.


Technically, the problem is that C++ function names are mangled, and
this mangling is implementation dependant! The signature of the
function is encoded into the external name of C++ functions.

So a C++ function such as int foo(int,char*); will actually be named
something like __Z3fooiPc in the object file.



From C code, compiled with a C program, you could call it as:

// C code:

extern int _Z3fooiPc(int i,char* c);

int f(){
char a[]="abc";
_Z3fooiPc(3,a);
}

Not funny.



The solution is to define C wrapper functions, in C++ (ie. you still
need the C++ compiler).

-------------------------------- c.cxx
// A C++ function:
int bar(int i,char* c){
return(c);
}

// A C++ function whose name won't be mangled:
extern "C" int foo(int i,char* c){
return(bar(i,c));
}
---------------------------------

% g++ -c -o c.o c.cxx && nm c.o
00000000 T __Z3bariPc
00000000 A __Z3bariPc.eh
00000014 T _foo
00000000 A _foo.eh


Notably, in the case of C++ objects, your wrapper will have to
explicitely pass the 'this' parameter:

-------------------------------- o.cxx
// A C++ class:
class Example {
int i;
public:
Example(int aI):i(aI){}
int foo(char* c){
return(c[this->i]);
}
};


// A C wrapper over the C++ class:
extern "C"{
typedef void* ExampleP;
ExampleP Example_new(int aI){ return new Example(aI); }
Example_foo(ExampleP that,char* c){ return(((Example*)that)->foo(c)); }

}
---------------------------------

% g++ -c -o o.o o.cxx && nm o.o
0000006c s EH_frame1
0000002c T _Example_foo
00000000 A _Example_foo.eh
00000000 T _Example_new
000000d0 S _Example_new.eh
00000056 S __ZN7Example3fooEPc
000000ac S __ZN7Example3fooEPc.eh
00000046 S __ZN7ExampleC1Ei
00000088 S __ZN7ExampleC1Ei.eh
U __Znwm
U ___gxx_personality_v0
 
M

mac

extern "C++"
If that was that easy!

As noted, C++ functions can be overloaded, so their names are extended
(mangled) to distinguish them.

But it goes much deeper than that. C++ has a more complex runtime
environment than C. Unless the C library is written to support both
languages, it may not handle some C++ features.

C++ code can have static constructors, which are called before main()
starts. C has no such thing (unless the standards committee has been
meddling), so there's no way a C program can initialize static C++ data.

C++ has exceptions, which C does not. So C code may not correctly handle
exceptions. C++ exceptions delete local objects as they go out of scope.
C won't.

C runtime, on the other hand, is pretty simple, so it's supported by C++.

Mixing malloc() and operator new may also lead to trouble.
Mixing stdio and iostreams is likely to lead to trouble.
 
R

Rainer Weikusat

[...]
C++ has exceptions, which C does not. So C code may not correctly handle
exceptions. C++ exceptions delete local objects as they go out of scope.
C won't.

That should have been 'C++ object can have destructors which are
automatically called for objects with storage class auto whenever
those go out of scope' (for instance, because of an exception).
Storage used by 'auto' objects themselves is freed when their lifetime
ends in C, too.
 
S

Scott Lurndal

mac said:
C++ code can have static constructors, which are called before main()
starts. C has no such thing (unless the standards committee has been
meddling), so there's no way a C program can initialize static C++ data.

From a standards perspective, perhaps. Most C implementations however
have some manner of pre-main initialization (e.g. .init/.fini sections
in the ELF file and shared objects).

scott
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,997
Messages
2,570,239
Members
46,827
Latest member
DMUK_Beginner

Latest Threads

Top