[net.lang.c++] Re.: C++ preprocessor wanted

bs@alice.UucP (Bjarne Stroustrup) (10/11/86)

Moshe Braner writes:

> Regarding the need for a C compiler that would handle long
> identifiers, y'all might not know that Megamax recognizes
> the first 10 chars, and allows very long total length.
> That may still not be enough for C++ - I dunno.

You can survive with C++ and only 31 significant characters in your C
compiler and linker. Don't try with less. If you have only 31 significant
characters complain (politely) to your compiler and linker supplier. Such
complaints have been known to have a positive effect - eventually.

> (and you still need to get that C++ preprocessor...)

The C++ translator, known as cfront, is a preprocessor only in the sense
that the UNIX C compiler is a preprocessor for an assembler. Calling it
a preprocessor is misleading.

Probably the best way of thinking of cfront is as the first pass in a
classical two pass compiler: cfront does a complete syntax check, a
complete type check, expands inline functions, adds temporary variables
where necessary, makes implicit initializations explicit, makes implicit
type coercions explicit, etc.; finally it produces an intermediate form
of the program to be read by the second pass. Using C as the intermediate
form is very useful for portability.

Any error messages produced by a C compiler while processing cfront output
is considered a bug in either cfront or the C compiler. By definition cfront
does not rely on the C compiler for anything but code generation.

> BTW: I devised a method to do object-oriented programming in C.
> Not fancy but simple, and you get inheritance and even late binding
> of sorts with high efficiency (about 100 microSecs for a typical
> invocation of a method).  If anybody is interested let me know.

This made me curious about what the cost of a C++ virtual function call
really is so I ran this example on a VAX11/750:

struct s {
	virtual f();
};

s::f() {}

main() {
	s* p = new s;

	for (int i = 100000; 0<i; i--) p->f();
}

It took 4 seconds; that is, about 4 microseconds per iteration.
For comparison I also ran

f() {}

main() {
	for (int i = 100000; 0<i; i--) f();
}

It took 3 seconds; that is, about 3 microseconds per iteration.
Finally I ran:

main() {
	for (int i = 100000; 0<i; i--) ;
}

It took .5 second. All timings are averages of several several runs.

These times were a bit disappointing in that I could measure the difference
between a virtual function call and a ``normal'' function call but, I think,
not bad. You can do a fair bit of work with a million function calls.

Maybe I ought to mention that with virtual functions there is no difference
between calling one virtual function twice compared with calling two virtual
functions once (many schemes for method lookup involves a slow first call
followed by fast subsequent calls so that simply invoking the same method
a million times would be a too easy test). No trickery, inlining, optimizing,
etc. was involved.

braner@batcomputer.TN.CORNELL.EDU (braner) (10/15/86)

[]

If 100000 calls take 4 seconds, that's 40 uS per call, not 4.

BTW, the 100 uS time I mentioned is for sending a method-token
to an object, complete with the lookup and the late binding.
And it is on the Atari ST.  For comparision, a standard C function
call (passing an integer both ways) has a 25 uS overhead, approximately.
Of course, any useful function (or method) would take at least another
20 uS to do its thing, and usually a lot longer.

- Moshe Braner

PS: I got many requests for the Object-Oriented C Programming.
I'll prepare a posting, one of these days.

robison@uiucdcsb.cs.uiuc.edu (10/16/86)

>	I just hope you never have a bug.  Sdb is only fair as a debugger
>	for C++.  But if you generated names that could not be easily
>	transformed by programmers to what they wrote in C++ sdb would be
>	just about useless.
>	The way I see it you'll need to write your own debugger at the
>	same time.

Actually, it's not that hard.  You just need a filter which maps long
names to short names, and saves the mapping as a file.  When you call
up the debugger, you put the filter between you the debugger's stdin,
and the inverse filter between the debugger's stdout and yourself.

I've used this trick to run a 7-character lint on long-identifier programs
without any problems.  The input to lint is mapped long-to-short and the
output of lint is mapped short-to-long.  In fact, most users which use 
this filtered version of lint are probably not aware that it is hacked so.

(Incidently, one easy mapping method is to hash the long identifiers
and use the hash address as the short identifier.)


Arch D. Robison					robison@uiucdcs
University of Illinois at Urbana-Champaign

P.S. My filter is free for the asking.  Its not very big. 

gnu@hoptoad.uucp (John Gilmore) (10/17/86)

> >                        ...you get inheritance and even late binding
> > of sorts with high efficiency (about 100 microSecs for a typical
> > invocation of a method).

In article <6174@alice.uUCp>, bs@alice.UucP (Bjarne Stroustrup) writes:
> This made me curious about what the cost of a C++ virtual function call
> really is so I ran this example on a VAX11/750:
> 
> 	for (int i = 100000; 0<i; i--) p->f();
> 
> It took 4 seconds; that is, about 4 microseconds per iteration.

Uh, if you run a loop 100,000 times in 4 seconds, that is *40* microseconds
per iteration, which sounds a lot more reasonable on a 750.  Remember that
this time includes the loop overhead, a function call, and a function return,
and Vaxes are slow about function calls.

Scale all the other "per iteration" numbers by a factor of 10 too.
-- 
John Gilmore  {sun,ptsfa,lll-crg,ihnp4}!hoptoad!gnu   jgilmore@lll-crg.arpa
(C) Copyright 1986 by John Gilmore.             May the Source be with you!