[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.c++

Is there anything special I need to do in order to mix object files created by the C and the C++ compilers?

Ramon F Herrera

9/10/2009 11:49:00 PM


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

9 Answers

Ramon F Herrera

9/10/2009 11:51:00 PM

0

On Sep 10, 7:49 pm, Ramon F Herrera <ra...@conexus.net> wrote:
> 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

joshuamaurice

9/10/2009 11:56:00 PM

0

On Sep 10, 4:49 pm, Ramon F Herrera <ra...@conexus.net> wrote:
> 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.

Sam

9/11/2009 12:13:00 AM

0

Ramon F Herrera writes:

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

Nope. g++.


Ramon F Herrera

9/11/2009 12:20:00 AM

0

On Sep 10, 7:55 pm, Joshua Maurice <joshuamaur...@gmail.com> wrote:
> On Sep 10, 4:49 pm, Ramon F Herrera <ra...@conexus.net> wrote:
>
> > 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.


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

pjb

9/11/2009 1:41:00 AM

0

Ramon F Herrera <ramon@conexus.net> writes:

> 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[i]);
}

// 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





--
__Pascal Bourguignon__

Christian Gollwitzer

9/11/2009 8:38:00 AM

0

Pascal J. Bourguignon schrieb:
> Ramon F Herrera <ramon@conexus.net> writes:
>> How about the opposite, how should I refer to to an extern C++
>> function?
>>
>> Let me guess:
>>
>> extern "C++"
>
> If that was that easy!
>
> 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.

You can, however, use C++ code inside an extern "C" function. The
easiest way is therefore, to make an interface

extern "C" {
int foo_for_C(int a, char*s);
}

int foo_for_C(int a, char*s) {
return foo(a, s);
}

which you compile with the c++-compiler.
Or, if the foo-function doesn't have a C++ interface, i.e. it is not
overloaded or a member function of some class, you can declare it
directly as being extern "C". Note, that the code in foo can use any C++
construct you wish, e.g. calling class members, overloaded functions,
use templates... because it is compiled with the c++ compiler.

Christian

mac

9/11/2009 6:18:00 PM

0

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

Rainer Weikusat

9/11/2009 6:33:00 PM

0

mac <alexc@theworld.com> writes:

[...]

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

scott

9/11/2009 7:55:00 PM

0

mac <alexc@theworld.com> writes:

> 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