[net.lang.c++] Standard C routines calling C++

bershad@ucbvax (Brian Bershad) (09/14/86)

I am running into a strange problem when linking in C++
code with Old C.

The following code shows what is happening:

/* THIS IS STANDARD C */
extern void foo();

main()
{
  int x = 23;
  foo(&x,&x);
}

----------------------------

/* THIS IS C++ */
#include <sys/types.h>
#include <sys/stat.h>

int lstat(char*, stat*);

void foo(int *x, int *y)
{
	struct stat stbuf;
	lstat("/etc/motd", &stbuf);

	return;
}

------------------------------------

and they are compiled as:
	% cc -c main.c
	% CC -c foo.c main.o


When I write into &stbuf via the lstat, the foo's return
address seems to get clobbered, and the program core
dumps with an illegal instruction at the return statement,
with the values for x and y getting set to nil.

After many hours, I discovered that if I say

void foo(int *x, int *y)
{
	struct stat* stbuf = new stat;
	.....
	delete stbuf;
	return;
}

things will work.... granted, this is what I want to
do, but not how I want to say it.

More annoyingly, the following core dumps in ostream...

void foo(int* x, int* y)
{
	cerr << *x;
	cerr << *y;
}

when it is called from a C program (for reasons that are beyond
me... I can guess on the first example, but on this one, I have no
idea).

Since I am writing a fairly substantial package that uses
somebody else's RPC (with stubs generated in C) routines,
the fact that this stuff doesn't work is causing me numerous
headaches.

What is C++ expecting on the stack frame for non-member functions
that old C is not putting there???


	Brian Bershad
	University Washington Comp Sci
	brian@uw-bluechip.arpa
	bershad@ucbvax.berkeley.edu | ucbvax!bershad

bs@alice.UucP (Bjarne Stroustrup) (09/15/86)

> From: bershad@ucbvax (Brian Bershad)
> Subject: Standard C routines calling C++ (non-member) functions
> Organization: University of California at Berkeley
>
> I am running into a strange problem when linking in C++ code with Old C.
> 
> The following code shows what is happening:

	/* THIS IS STANDARD C */
	extern void foo();

	main()
	{
  	int x = 23;
  	foo(&x,&x);
	}

> ----------------------------

	/* THIS IS C++ */
	#include <sys/types.h>
	#include <sys/stat.h>

	int lstat(char*, stat*);

	void foo(int *x, int *y)
	{
		struct stat stbuf;
		lstat("/etc/motd", &stbuf);
	
		return;
	}

> ------------------------------------
> 
> and they are compiled as:
> 	% cc -c main.c
> 	% CC -c foo.c main.o
> 

> When I write into &stbuf via the lstat, the foo's return
> address seems to get clobbered, and the program core
> dumps with an illegal instruction at the return statement,
> with the values for x and y getting set to nil.

I conjecture that you are using a SysV declaration of ``struct stat'' in
/usr/include/CC/sys/stat.h from C++ and a BSD4.? declaration ``struct stat''
in /usr/include/sys/stat.h from C. Since the BSD stat is larger than the SysV
stat you are in trouble. Please modify /usr/include/CC/sys/stat.h to fit
your system.

> More annoyingly, the following core dumps in ostream...
> 
> void foo(int* x, int* y)
> {
> 	cerr << *x;
> 	cerr << *y;
> }
> 
> when it is called from a C program (for reasons that are beyond
> me... I can guess on the first example, but on this one, I have no
> idea).

I conjecture that you did not load the program using CC so that the constructors
initializing cin, cout, and cerr were not called. A similar effect (core dump
on the first C++ stream I/O operation) can be obtained by not compiling main()
by CC.

> Since I am writing a fairly substantial package that uses
> somebody else's RPC (with stubs generated in C) routines,
> the fact that this stuff doesn't work is causing me numerous
> headaches.

Sorry about that, and thankyou for complaining where others can benefit from
your experiences. It ought to work. Please confirm or complain again.
 
> What is C++ expecting on the stack frame for non-member functions
> that old C is not putting there???

Nothing, C++ does not diddle with stack layouts or with structure layouts for
functions or structures that can be expressed in C.

>	Brian Bershad
>	University Washington Comp Sci
>	brian@uw-bluechip.arpa
>	bershad@ucbvax.berkeley.edu | ucbvax!bershad

brian@uw-june (Brian Bershad) (09/23/86)

This is in response to BS's very helpful response on
problems involving integrating c++ with standard c.

Problem 1:


>	/* THIS IS STANDARD C */
>	extern void foo();
>
>	main()
>	{
>  	int x = 23;
>  	foo(&x,&x);
>	}
>
>> ----------------------------
>
>	/* THIS IS C++ */
>	#include <sys/types.h>
>	#include <sys/stat.h>
>
>	int lstat(char*, stat*);
>
>	void foo(int *x, int *y)
>	{
>		struct stat stbuf;
>		lstat("/etc/motd", &stbuf);
>	
>		return;
>	}
>
> ------------------------------------
> 
> and they are compiled as:
> 	% cc -c main.c
> 	% CC -c foo.c main.o
> 
>
> When I write into &stbuf via the lstat, the foo's return
> address seems to get clobbered, and the program core
> dumps with an illegal instruction at the return statement,
> with the values for x and y getting set to nil.
>

BS's response:
>>I conjecture that you are using a SysV declaration of ``struct stat'' in
>>/usr/include/CC/sys/stat.h from C++ and a BSD4.? declaration ``struct stat''
>>in /usr/include/sys/stat.h from C. Since the BSD stat is larger than the SysV
>>stat you are in trouble. Please modify /usr/include/CC/sys/stat.h to fit
>>your system.

Yes. Exactly.  I have since converted all of the 4.3 /usr/include
files to work with C++.  

> More annoyingly, the following core dumps in ostream...
> 
> void foo(int* x, int* y)
> {
> 	cerr << *x;
> 	cerr << *y;
> }
> 
> when it is called from a C program (for reasons that are beyond
> me... I can guess on the first example, but on this one, I have no
> idea).

BS's response:

>>I conjecture that you did not load the program using CC so that the constructors
>>initializing cin, cout, and cerr were not called. A similar effect (core dump
>>on the first C++ stream I/O operation) can be obtained by not compiling main()
>>by CC.

You got it.
Yes, they were loaded properly.
The problem seems to only happen when you call a C++ function from 
standard C main().  If I reverse the calling sequence, things work.
I guess, in retrospect, this makes sense.

> Since I am writing a fairly substantial package that uses
> somebody else's RPC (with stubs generated in C) routines,
> the fact that this stuff doesn't work is causing me numerous
> headaches.
>
>>Sorry about that, and thankyou for complaining where others can benefit from
>>your experiences. It ought to work. Please confirm or complain again.

No apologies needed. 
In general, integrating large amounts of C code (> 500 lines) with
large amounts of C++ code (> 5000 lines), seems to work ok.  I
have some nasty sed/awk scripts to clean up the RPC generated headers
for the stubs to make them both C and C++ compatible, and there are still some 
strange problems with passing enumerated types between C and C++,
but things are going well, and I don't think I would have
been able to handle this much code as effectively had I done
it in C.  (though I still have to convince my advisor
that doing this in C++ was a good idea...... )

I have an unrelated (possibly naive) question.  I am using dbx
to debug my code, and I was rather surprised to find that
dbx can relate C++ statements (not those in the ..c files)
to the pc, so I can smoothly trace execution from the debugger.
I have to do all the name translation by hand (ie. Class::function
becomes Class_function, prepending _auto_ to most things, etc...),
but dbx is able to map my .c source code to the executable so
I can trace through things and see the original C++ code.
Since it is really the ..c files that are being compiled with
/bin/cc, how is dbx able to do this??  This is not a complaint.


	Brian Bershad
	University of Washington Computer Science
	bershad@ucbvax.berkeley.edu || ucbvax!bershad || brian@uw-june.arpa

ark@alice.UucP (Andrew Koenig) (09/26/86)

> I have an unrelated (possibly naive) question.  I am using dbx
> to debug my code, and I was rather surprised to find that
> dbx can relate C++ statements (not those in the ..c files)
> to the pc, so I can smoothly trace execution from the debugger.
> I have to do all the name translation by hand (ie. Class::function
> becomes Class_function, prepending _auto_ to most things, etc...),
> but dbx is able to map my .c source code to the executable so
> I can trace through things and see the original C++ code.
> Since it is really the ..c files that are being compiled with
> /bin/cc, how is dbx able to do this??  This is not a complaint.

Cfront uses the same mechanism the C preprocessor uses to communicate
line numbers to the C compiler proper.

In other words:  when you say  #include "foo.h"  the C compiler knows
to give you error messages referring to foo.h rather than to your
source file, even though all it actually sees is one long stream of
text.  This happens because the C preprocessor inserts magic cookies
into its output saying "the following stuff comes from line p of file q."

Cfront uses exactly the same mechanism.

jsdy@hadron.UUCP (Joseph S. D. Yao) (10/01/86)

In article <1221@uw-june> brian@uw-june.UUCP (Brian Bershad) writes:
>> More annoyingly, the following core dumps in ostream...
>> void foo(int* x, int* y) ...
>> when it is called from a C program (for reasons that are beyond
>BS's response:
>>>I conjecture that you did not load the program using CC so that the constructors
>>>initializing cin, cout, and cerr were not called. A similar effect (core dump
>>>on the first C++ stream I/O operation) can be obtained by not compiling main()
>>>by CC.
>You got it.
>Yes, they were loaded properly.
>The problem seems to only happen when you call a C++ function from 
>standard C main().  If I reverse the calling sequence, things work.
>I guess, in retrospect, this makes sense.

In the C++ that I installed, there is a clearly defined procedure
to make C++ run from C.  One must call a certain routine from main()
before calling any C++.  It is not in the book, so it must be in the
installation instructions (which I do not have near me).  Check
there.
-- 

	Joe Yao		hadron!jsdy@seismo.{CSS.GOV,ARPA,UUCP}
			jsdy@hadron.COM (not yet domainised)