[comp.lang.c++] Mixing C with C++

gas@cs.nott.ac.uk (Alan Shepherd) (04/22/91)

About a week ago I posted an article asking for help with a problem I
was having with making C++ functions (not methods) callable from C++.

I've had quite a response so I thought other people might be
interested in the necessary details.  The first thing to do is to
declare your C++ function to have C linkage (even though you compile
it with C++) e.g.

extern "C" void aC++Fn();

void aC++Fn()
{
	cout << "A C++ Function" << endl;
}

This is the easy bit.  The second step involves linking using C++ and
not C.  Most of my replies pointed this out, but I had done this and
still encountered problems (sorry for not pointing this out before).
The crucial step is that the file with main() needs to be compiled
using C++ even if it is in a c file.  Thanks to those people who
pointed this out.

I felt a bit of an idiot when I realised the solution, but several of
my replies missed this too, so I don't feel quite so bad....:-)

Alan Shepherd

strollo@ssd.kodak.com (larry strollo ) (04/23/91)

In article <1991Apr22.064847.16929@cs.nott.ac.uk> gas@cs.nott.ac.uk () writes:

>> 
>> I've had quite a response so I thought other people might be
>> interested in the necessary details.

...... particulars deleted ........

>> 
>> This is the easy bit.  The second step involves linking using C++ and
>> not C.  Most of my replies pointed this out, but I had done this and
>> still encountered problems (sorry for not pointing this out before).

I'm confused.  Since the linker is just linking object files (generated from
C I might add), what is special about the C++ "linker" ?  Do you really mean
that some special C++ libraries are linked in (in which case I should be able
to do the same thing by just explicitly calling out the libraries in the link
command, shouldn't I) ?

>> The crucial step is that the file with main() needs to be compiled
>> using C++ even if it is in a c file.  Thanks to those people who
>> pointed this out.
>> 

I'm working on a set of programs that are going to be implemented in C++,
but must provide an interface callable from C.  It's probably not going to 
be reasonable for me to insist that the user have Cfront.  Am I in trouble ? 

>> I felt a bit of an idiot when I realised the solution, but several of
>> my replies missed this too, so I don't feel quite so bad....:-)
>> 
>> Alan Shepherd
>> 
>> 

Not nearly as bad as I'm going to feel if the answer to my last question
is "yes" !    |8-}

Larry Strollo
strollo@ssd.kodak.com]


-- 
------------------------------------------------------------------------------
Larry Strollo             strollo@ssd.kodak.com                 (716) 726-0901
Integration & Systems Products Division     Eastman Kodak Co      Rochester NY
------------------------------------------------------------------------------

steve@taumet.com (Stephen Clamage) (04/24/91)

strollo@ssd.kodak.com (larry strollo ) writes:

>In article <1991Apr22.064847.16929@cs.nott.ac.uk> gas@cs.nott.ac.uk () writes:

>>> This is the easy bit.  The second step involves linking using C++ and
>>> not C.  Most of my replies pointed this out, but I had done this and
>>> still encountered problems (sorry for not pointing this out before).

>I'm confused.  Since the linker is just linking object files (generated from
>C I might add), what is special about the C++ "linker" ?

Usually linking is done via the cc or CC driver program (or whatever it is
called on your system).  The C++ version of the driver (or the driver
when told to operate in C++ mode) does different things for C++ than
for C.  If you know the ultimate linking command, you can use that
command directly, if less conveniently.  Sometimes the C++ driver runs
separate post-linking commands, which you would have to remember
to do as well.

>I'm working on a set of programs that are going to be implemented in C++,
>but must provide an interface callable from C.  It's probably not going to 
>be reasonable for me to insist that the user have Cfront.  Am I in trouble ? 

Not necessarily.  All C++ compilers I am familiar with require that
main() be compiled with with the C++ compiler.  This does not mean
that the user must have a C++ compiler to use your programs.

You write the actual main() in its own module like this:
	extern int my_main(int, char**);
	main(int argc, char** argv)
	{
	    return my_main(argc, argv);
	}
Compile it with the C++ compiler, and put it in your library.  Instruct
your users to write their main() with the name "my_main" instead.
Everything should just work.

In some cases, the user might want main() to take additional parameters,
one common variation being
	main(int argc, char** argv, char** environment)
You might have to provide several versions of main() in that case,
and at most one of them could be put into a library; the others
would have to be separate object files.
-- 

Steve Clamage, TauMetric Corp, steve@taumet.com

cooker@newsrice.edu (Donald George Baker) (04/24/91)

In article <1991Apr23.133931.6716@ssd.kodak.com>, strollo@ssd.kodak.com (larry strollo ) writes:
|> 
|> I'm confused.  Since the linker is just linking object files (generated
|> from C I might add), what is special about the C++ "linker" ?  Do you
|> really mean that some special C++ libraries are linked in (in which case I
|> should be able to do the same thing by just explicitly calling out the
|> libraries in the link command, shouldn't I) ?

I can see that there is still a lot of confusion about what is happening with
the C++ linker and how it relates to mixing in pure C code.  Besides linking
against the C++ library, the linker does the interesting part of getting the
constructors and destructors for global objects called at the right time. 
Note:  these comments refer to AT&T's CFront, so your milage may vary.

The C++ linker actually links a program twice.  The first time to make an
executable on which 'nm' can be run.  The second pass looks for routines that
follow a particular naming convention.  These routines are the constructors
and destructors for global objects.  The routines are gathered up and put into
two tables.  The order in which these appear is totally dependent on the
linking order--a serious problem with global objects.  A routine called _main
will call all of the constructors and _exit (I think) calls all of the
destructors.  It is hard not to have the destructors called, because you must
link against the special _exit, but when your main program is not C++, _main
does not get called automatically.  All you need to do is call _main() with
no arguments yourself.

I hope this helps.

-----------------------------------------------------------------------------
 Donald G. Baker  (cooker@Rice.edu)    \	Computer Science Department,
    Computer-human interaction,		\	Rice University
    Programming environments,		/\	P. O. Box 1892
    Software engineering	       /  \	Houston, TX  77251-1892, USA
-----------------------------------------------------------------------------
-- 
-----------------------------------------------------------------------------
 Donald G. Baker  (cooker@Rice.edu)    \	Computer Science Department,
    Computer-human interaction,		\	Rice University
    Programming environments,		/\	P. O. Box 1892

pauld@stowe.cs.washington.edu (Paul Barton-Davis) (04/25/91)

As an example of what the "C++ linker" does that the "C linker" does
not: AT&T C++ 2.1 comes in two varieties, one called patch, the other
called munch. The patch version edits the object file produced by the
linker to fill in the addresses used to link the statics ctors and
dtors together. The munch version does this by running the link
editor/loader (whatever) twice. Getting this functionality yourself is
tedious, but obviously could be done, especially since the "patch"
code is a separate process run by the CC script.

-- 
Paul Barton-Davis			<pauld@cs.washington.edu>
					 UW Computer Science Lab	 

"People cannot cooperate towards common goals if they are forced to

steve@taumet.com (Stephen Clamage) (04/25/91)

steve@taumet.com (Stephen Clamage) writes:

>You write the actual main() in its own module like this:
>	extern int my_main(int, char**);
>	main(int argc, char** argv)
>	{
>	    return my_main(argc, argv);
>	}
>Compile it with the C++ compiler, and put it in your library.  Instruct
>your users to write their main() with the name "my_main" instead.
>Everything should just work.

Oops!  I forgot two very important points.

1.  Unless you supply the C++ runtime library and any special startup
modules (some systems provide a replacement crt0.o or equivalent),
or you will have to pre-link your entire library with the C++ runtimes
and supply it as a single object module.  Otherwise, things may turn
up missing when a user tries to link a program.

2.  Most C++ implementations require steps to be done after linking.
(Cfront requires "patch" or "munch", Oregon C++ requires "cdlink".)
Any application with static objects requiring constructors or
destructors (such as stream I/O) will require this step.  You will have to
experiment to see if the step can be omitted when there are no static
objects.
-- 

Steve Clamage, TauMetric Corp, steve@taumet.com

joe@proto.com (Joe Huffman) (04/27/91)

steve@taumet.com (Stephen Clamage) writes:

>Not necessarily.  All C++ compilers I am familiar with require that
>main() be compiled with with the C++ compiler.  This does not mean

You must not be familiar with the Zortech Compiler.  It does not have that
requirement.

-- 
joe@proto.com