Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Compile speed: Pascal(Delphi) vs C++

643 views
Skip to first unread message

Chavoux

unread,
Nov 11, 2003, 1:56:47 PM11/11/03
to
Hi

A question: my brother wrote the same programme (fairly large and
using database and networking) in both Delphi and Borland C Builder.
Apparantly the C Builder version took huge ammounts of time to
compile. (So much so that he switched back to rewriting everything in
Delphi).

I am not familiar at all with the internals of the compilers of these
languages, but I would like to know why this is the case? I have heard
a few times that C (and C++?) programs tend to be very fast at
runtime, but to compile slowly. Is this only a problem with the
specific implimentation (Borland) of the two languages? E.g. do Gnu
g++/gcc and Gbu Pascal compile equally fast? Or might it have
something to do with the fact that you always have to declare
variables before you use or initialize them in Pascal whereas you can
do it inline for C++? (I.o.w. maybe the Pascal is a real one-time pass
compiler, whereas C compromised on this somewhere along the line?) Or
does it have something to do with the OS and API... (i.e. C++ assume
the availability of the C libraries...available under linux, but not
by default in Windows...whereas Delphi's "libraries" are mostly
wrappers around the Windows API...so there is less actual code to
compile for the Delphi)? AFAIK static linking is always needed on
programmes written for Windows because you can't assume that the C
libraries will be available on the user's PC. These are just possible
causes I can think of (maybe totally off the mark), so please correct
me where my assumptions are wrong.

Regards
Chavoux
[It entirely depends on how the compiler's designed. Turbo C was very
fast but did only modest amounts of optimization. It looks like later
versions stopped paying attention to compile speed and concentrated on
optimizing. -John]

Lucian Wischik

unread,
Nov 11, 2003, 11:05:42 PM11/11/03
to
Cha...@yahoo.com (Chavoux) wrote:
>A question: my brother wrote the same programme (fairly large and
>using database and networking) in both Delphi and Borland C Builder.
>Apparantly the C Builder version took huge ammounts of time to
>compile. (So much so that he switched back to rewriting everything in
>Delphi).
>I am not familiar at all with the internals of the compilers of these
>languages, but I would like to know why this is the case?

In Pascal, when you import a unit's interface, it can be imported just
as a straight binary dump of the symbol table. In C++, when you
#include a header file, it has to include it textually because
previous stuff (e.g. #defines) can completely change the meaning of a
header file. That means that each .cpp file amounts to 25,500 lines of
code that the compiler has to parse -- 25,000 for the headers, 500 for
the code. In Pascal it only parses 500 lines.

Well, this isn't quite true. In C++Builder and Visual Studio and
probably other C++ compilers, you can use extra directives to let the
compiler use "precompiled headers" -- ie. if two .cpp files use
exactly the same headers, in exactly the same sequence, with no clever
features, then the compiler can save a binary dump of this. In
C++Builder the .pch files take upwards of 15Mb. (whereas the pascal
unit files take maybe 50k each -- so there's still the speed
difference).


I remember the story of the C programmer who switched to Delphi, wrote
a very large program, clicked the Compile button, and nothing seemed
to happen. He thought there must have been a bug in the Delphi IDE.
Why wasn't it compiling? -- turns out it was compiling the entire
program, in a fraction of a second, so quickly he hadn't even noticed.
(I understand that Borland put a lot more effort into fast-compilation
of Delphi than most compiler vendors do, but don't know where I heard
this.)

--
Lucian

Fergus Henderson

unread,
Nov 11, 2003, 11:05:21 PM11/11/03
to
Cha...@yahoo.com (Chavoux) writes:

>I am not familiar at all with the internals of the compilers of these
>languages, but I would like to know why this is the case?

One reason why Delphi may be faster to compile than C++ is that Delphi
has a proper module system, whereas C++ still uses the old #include
preprocessor hack. The old #include hack has the drawbacks that the
meaning of each header file included may depend on what macros are in
scope at that point. So the effect of including header files in a
different order might be different. This makes precompilation of
header files much more difficult, complicated, and ineffective than
for Turbo Pascal units. As a result, C++ compilers tend to parse the
headers each time they are read, rather than precompiling them.

Our moderator writes:

>[It entirely depends on how the compiler's designed.

Not entirely -- it also depends on how the language was designed.
Some languages are easier to compile quickly than others.

--
Fergus Henderson <f...@cs.mu.oz.au> | "I have always known that the pursuit
The University of Melbourne | of excellence is a lethal habit"
WWW: <http://www.cs.mu.oz.au/~fjh> | -- the last words of T. S. Garp.

Marco van de Voort

unread,
Nov 21, 2003, 12:36:35 AM11/21/03
to
On 2003-11-11, Chavoux <Cha...@yahoo.com> wrote:
>
> A question: my brother wrote the same programme (fairly large and
> using database and networking) in both Delphi and Borland C Builder.
> Apparantly the C Builder version took huge ammounts of time to
> compile. (So much so that he switched back to rewriting everything in
> Delphi).

A similar question has already been on this list before, see
http://compilers.iecc.com/comparch/article/02-07-128

Traditionally there are four reasons, though some of these don't apply to
this case:

- C/C++ parses slower than Pascal in theory. This is effect negiable
- The unit system vs headers. Lucian already answered that adequately
- (when compared to Turbo Pascal), TP optimizes hardly, optimizing also
costs time. This should matter much in this case, since BCB++ and Delphi
should be in the same league. This is what our moderator meant
I guess.
- (when comparing a Borland (or compatible) pascal compiler to GNU gcc), the
gcc build process is quite involved, with external preprocessors,
linkers etc. This should not be underestimated, see the above thread for
more info.

I think the problem in this case (BCB++ vs Delphi) is still the unit
system, despite BC++ already contains a lot more handling to speed it
up, unless the BC++ also calls external tools, which seriously I
doubt.

> [It entirely depends on how the compiler's designed. Turbo C was very
> fast but did only modest amounts of optimization. It looks like later
> versions stopped paying attention to compile speed and concentrated on
> optimizing. -John]

Delphi and BCB++ should optimize in the same magnitude.

Rob Thorpe

unread,
Nov 21, 2003, 12:41:53 AM11/21/03
to
Most of the reason is that Borland traditionally take great pains to
make their compilers fast. There are some aspects of the C++ and C
languages that make the languages difficult to compile quickly. Here
are a few common problems.

1) The compiler

Borlands compilers are optimized for speed, not to give good code. In
the quite recent past they were written in assembly language. Pascal
is marginally easier to parse than C, so the compiler has more scope
for speed. Both are easier to parse (and therefore potentially
faster) than C++.

As far as optimizations go, what is important is not how good the
compiler is, but how good it is at its highest setting. Set it to
almost no optimization for debugging and only use optimization when
you get near to the final release. So in principle there is no good
reason why a compiler shouldn't be fast and give good code on the
final build. In practice I haven't found one thats both very good and
very fast.

Some compilers have always been better than others.

2) Header files
As other posters have mentioned header files take time to compile. This
can cause problems in several situations:-

- You've written a program that includes one huge header file everywhere
when most of it isn't needed everywhere. This is completely brain dead
programming but not uncommon since header files grow in size over time.
It happens quite a lot in C++ because many people who write it don't
understand it very well.

- You've written a program where one header file really is needed
everywhere. In that case, sorry but C'est la vie.

- Some idiot has written libraries that require huge header files. For
instance including the C++ iostreams header file on the computer I'm
sitting at produces a file 21000 lines long. This is mainly the fault
of the designers of the C++ standard, I'm tempted to say some very
impolite things about them, but I'll resist it for now.

If you have a compiler with caching pre-compiled headers these problems
will be reduced significantly.

3) Going through assembly langauge.

Some C compilers compile to assembly language and then invoke the
assembler, this causes some overhead.

4) Being unable to pipe between the parts of the compiler

The compiler should use pipes to communicate with the preprocessor and
the assembler, in some cases it won't so there will be some extra
overhead reading a writing files.

5) Misusing recursive make

Makefiles invoking other makefiles and doing things twice. A good
reason to avoid recursive make.

Randall Hyde

unread,
Nov 21, 2003, 12:48:55 AM11/21/03
to
"Lucian Wischik" <lu...@wischik.com> wrote in message news:03-11-

>
> (I understand that Borland put a lot more effort into fast-compilation
> of Delphi than most compiler vendors do, but don't know where I heard
> this.)

The Delphi compiler is a direct descendant of the Turbo Pascal compiler,
which, of course, was written to compile code as quickly as possible.

Pascal's one-pass language design also helps with speedy compiles.
C (and especially C++) requires considerable more effort, particularly
if you use templates. Also, don't forget the preprocessor pass (though
this rarely costs a significant amount of time outside processing all
the header files).
Cheers,
Randy Hyde

VBDis

unread,
Nov 21, 2003, 12:46:14 AM11/21/03
to
Fergus Henderson <f...@cs.mu.oz.au> schreibt:

>Our moderator writes:
>
>>[It entirely depends on how the compiler's designed.
>
>Not entirely -- it also depends on how the language was designed.
>Some languages are easier to compile quickly than others.

I also think that it's more a matter of the language than of the compiler. But
what exactly makes an Delphi compiler more than 10 times faster than an C/C++
compiler? Some ideas:

- the use of header files instead of precompiled units
- the extra C preprocessor stage and macro expansion
- C requires larger symbol tables
- C is harder to parse
- C is harder to optimize
- C source code for the same purpose is much longer(???)
- C is slow in text handling (provided the Delphi compiler is not written in C
;-)

Even if the use of header files seems to be the most important disadvantage of
C, some people say that it's the C syntax which makes the compilers so slow. I
tend to agree with the syntax issue, but without any proof, it's only a feeling
for now. The speed boost with precompiled header files is noticeable, but why?
Is it only lazyness why the use of header files has not been replaced by more
appropriate procedures, in the past decades? And is a C# compiler so much
faster than a C++ compiler, due to its use of precompiled assemblies? What
about incremental compilers?

Unfortunately the other topics cannot be verified, as long as the impact of the
header files cannot be separated from the other compiler activities. So I only
know that C is not an appropriate language for RAD, and no attempts, worth to
mention, have been made in the past to change that :-(


I also have no experience for a comparison of Turbo C with Turbo Pascal, but
Turbo C may have been faster than nowadays C++ compilers only due to the fewer,
simpler, shorter, and less nested header files of that time. At least I doubt
that it was the lack of optimization, which made Turbo C quite fast, because
then Delphi had to be quite slow for its much better optimization. Or is it so
much more complicated to optimize C programs, as opposed to Pascal/OPL code?

DoDi

Marco van de Voort

unread,
Dec 3, 2003, 5:51:59 PM12/3/03
to
On 2003-11-12, Lucian Wischik <lu...@wischik.com> wrote:
> Cha...@yahoo.com (Chavoux) wrote:
>>A question: my brother wrote the same programme (fairly large and
>>using database and networking) in both Delphi and Borland C Builder.
>>Apparantly the C Builder version took huge ammounts of time to
>>compile. (So much so that he switched back to rewriting everything in
>>Delphi).
>>I am not familiar at all with the internals of the compilers of these
>>languages, but I would like to know why this is the case?
>
> In Pascal, when you import a unit's interface, it can be imported just
> as a straight binary dump of the symbol table.

Yes, but you have the burden of automake (automatically remake if files
changed), so you have to check if all source files (.pas and .inc) and
dependant units are in sync.

The fact that typical (Borland) Pascal compilers compile a whole string of
units in one go helps though. The dependant units are often already loaded
into mem.

C usually puts that burden on make.

Marco van de Voort

unread,
Dec 3, 2003, 5:51:43 PM12/3/03
to
On 2003-11-21, VBDis <vb...@aol.com> wrote:

> - the extra C preprocessor stage and macro expansion
> - C requires larger symbol tables
> - C is harder to parse
> - C is harder to optimize
> - C source code for the same purpose is much longer(???)
> - C is slow in text handling (provided the Delphi compiler is not written in C
> ;-)

The Delphi compiler is written in C++.

The FPC compiler (delphi clone) is written in itself (Object Pascal).

> I also have no experience for a comparison of Turbo C with Turbo Pascal,
> but Turbo C may have been faster than nowadays C++ compilers only due to
> the fewer, simpler, shorter, and less nested header files of that time.

... and the fact it was probably written in handcoded and handtuned asm.
More time was invested in making programs run fast in that era.
[Turbo C was written in C. I used its predecessor Wizard C compiler which
was really nice. To turbo-ize it they buffered lots more source material
in RAM. -John]

Robert A Duff

unread,
Dec 3, 2003, 8:21:54 PM12/3/03
to
Rob Thorpe <robert...@antenova.com> writes:

[snipped a lot of good stuff I agree with, but...]

> As far as optimizations go, what is important is not how good the
> compiler is, but how good it is at its highest setting. Set it to
> almost no optimization for debugging and only use optimization when
> you get near to the final release.

No! Optimization sometimes introduces new bugs. Yes, use
no-optimization for debugging (usually). But don't wait until
near-final-release to run with optimization turned on. Instead, have a
good regression test suite, and run it every night at 2 am or so, with
optimization both on and off.

- Bob

Torben Ægidius Mogensen

unread,
Dec 8, 2003, 12:15:45 AM12/8/03
to
Robert A Duff <bob...@shell01.TheWorld.com> writes:

> Optimization sometimes introduces new bugs.

I would hate to think that compiler writers make optimizations that
break language semantics. I know this can happen by mistake and that
earlier compilers were notorious for having buggy optimizations, but
with modern optimization techniques that shouldn't happen.

I have a feeling that in many cases optimization (in modern compilers)
not so much introduce bugs as reveal cases where the programmer made
unwarranted assumptions about language semantics, such as order of
computation, arithmetic precision, and other things.

I recall one such experience: I wrote a program (in C) that included a
function to find the shortest edge of an irregular tetrahedron with
vertices A, B, C and D. It did that roughly by

shortest(A,B,C,D) =
if |A-C| < |A-B| then shortest (A,C,B,D)
else if |A-D| < |A-B| then shortest(A,D,C,B)
else if |B-C| < |A-B| then shortest(B,C,A,D)
else if (more tests)
else (A,B)

Not very efficient I grant you, but that wasn't the problem. The
problem was that optimization combined a*b+c (part of the |A-B|
computation) into one MAC instruction, which changed the precision
such that you could have that |A-C|<|A-B| and then after swapping B
and C (i.e., C'=B, B'=C), you would in the next call also have
|A-C'|<|A-B'|, which caused infinite recursion.

I don't blame the compiler. I was foolish to treat floating-point
numbers as exact, i.e., expecting that if |A-B|=|A-C|, then I wouldn't
get a "<" result.

Torben Mogensen

Joachim Durchholz

unread,
Dec 8, 2003, 12:19:12 AM12/8/03
to
Marco van de Voort wrote:

>> In Pascal, when you import a unit's interface, it can be imported
>> just as a straight binary dump of the symbol table.
>
> Yes, but you have the burden of automake (automatically remake if
> files changed), so you have to check if all source files (.pas and
> .inc) and dependant units are in sync.

The difference is that, for a typical Windows program, you have to
recompile approximately five megabytes of header files
IIRC. (Stripping out comments and whitespace leaves you with a few
100K of relevant information, which still means a lot of symbol table
building.)

Having to remake a few files occasionally is still a clear win.

> The fact that typical (Borland) Pascal compilers compile a whole
> string of units in one go helps though. The dependant units are often
> already loaded into mem.

If that were the case, precompiled headers would close the gap from
standard C++ usage to Turbo Pascal. In practice, Turbo Pascal still
blows the socks off C++ (well, compiling several thousand lines of
code in fractions of a second on a '486 is really hard to beat).

Regards,
Jo

Fabian Giesen

unread,
Dec 8, 2003, 12:26:58 AM12/8/03
to
Randall Hyde wrote:
> The Delphi compiler is a direct descendant of the Turbo Pascal compiler,
> which, of course, was written to compile code as quickly as possible.
>
> Pascal's one-pass language design also helps with speedy compiles.
> C (and especially C++) requires considerable more effort, particularly
> if you use templates. Also, don't forget the preprocessor pass (though
> this rarely costs a significant amount of time outside processing all
> the header files).

C++ is a different story, but C (after preprocessing is done) can easily
be compiled by a one-pass compiler (e.g. LCC does this).

-fg

Robert A Duff

unread,
Dec 13, 2003, 9:11:09 PM12/13/03
to
tor...@diku.dk (Torben Ægidius Mogensen) writes:

> Robert A Duff <bob...@shell01.TheWorld.com> writes:
>
> > Optimization sometimes introduces new bugs.
>
> I would hate to think that compiler writers make optimizations that
> break language semantics.

I hate it, too, but nonetheless, compilers do have bugs. Sometimes
these bugs are triggered by turning on optimization. Sometimes by
turning off optimization.

>...I know this can happen by mistake and that earlier compilers were


>notorious for having buggy optimizations, but with modern
>optimization techniques that shouldn't happen.

It shouldn't, but it does. Using "modern optimization techniques" is
all well and good, but it doesn't eliminate compiler bugs,
unfortunately.

> I have a feeling that in many cases optimization (in modern
> compilers) not so much introduce bugs as reveal cases where the
> programmer made unwarranted assumptions about language semantics,
> such as order of computation, arithmetic precision, and other
> things.

Quite true. When I said, "Optimization sometimes introduces new
bugs", I wasn't trying to place the blame. Those bugs could be
optimizer bugs, or they could be the programmer's fault. Either way,
turning on optimizations can cause the program being compiled to
misbehave. My point was simply that if you want to do development
using a no-optimize/debug build, but release an optimized version,
then you would be wise to have a nightly-run script that runs all your
regression tests in *both* modes.

Whether languages ought to have such nondeterministic semantics is
another question. Java tries to nail things down more precisely than
Ada or C, for example. With regard to order of evaluation of
arguments, for example.

I'm currently working on a tool that can (among other things) prove
statically that order of evaluation of arguments doesn't matter --
place certain restrictions on the arguments, and then you can be sure
that F(X, Y) produces the same results whether X or Y is evaluated
first.

> I recall one such experience: I wrote a program (in C) that included a
> function to find the shortest edge of an irregular tetrahedron with
> vertices A, B, C and D. It did that roughly by
>
> shortest(A,B,C,D) =
> if |A-C| < |A-B| then shortest (A,C,B,D)
> else if |A-D| < |A-B| then shortest(A,D,C,B)
> else if |B-C| < |A-B| then shortest(B,C,A,D)
> else if (more tests)
> else (A,B)
>
> Not very efficient I grant you, but that wasn't the problem. The
> problem was that optimization combined a*b+c (part of the |A-B|
> computation) into one MAC instruction, which changed the precision
> such that you could have that |A-C|<|A-B| and then after swapping B
> and C (i.e., C'=B, B'=C), you would in the next call also have
> |A-C'|<|A-B'|, which caused infinite recursion.
>
> I don't blame the compiler. I was foolish to treat floating-point
> numbers as exact, i.e., expecting that if |A-B|=|A-C|, then I wouldn't
> get a "<" result.

Yes, that's an example of what I was talking about. If you test the
optimized version on a regular basis, you have a good chance of
knowing which change triggered the problem. If you wait until the
project is done, and *then* turn on the optimizer, and your tests
don't work, it's hard to figure out why.

As a compiler writer, I've received bug reports that blamed the
compiler, when actually the programmer was at fault. Doesn't matter
-- the program didn't work.

- Bob

Paul Robinson

unread,
Feb 4, 2004, 9:56:06 PM2/4/04
to
Chavoux wrote:

> I am not familiar at all with the internals of the compilers of these
> languages, but I would like to know why this is the case? I have heard
> a few times that C (and C++?) programs tend to be very fast at
> runtime, but to compile slowly.

There are a number of variables involved, including type of compiler,
how it was written, target, etc.

> [DELETED] (I.o.w. maybe the Pascal is a real one-time pass


> compiler, whereas C compromised on this somewhere along the line?)

Most Pascal compilers are in fact, true one pass compilers for the
simple reason that they can be. Since everything is pre declared, you
have no unknown forward references, the compiler can include stub
references for things that have been defined but not yet referenced
(that is, you know that an item will exist at some point later on in
the code but you don't know where it will be) then come back and do
fixups for those unknown forward pointers. Much, much faster than
having to keep bookkeeping of both undeclared and forward declared
items (in hope that they will be declared later) which is required for
C and C++.

Not to raise any language wars here, but C++ is simply a much more
complicated language with a lot more ways to do things in it than
Object Pascal and thus it is going to take more work to compile.
Also, Pascal is a rigidly defined language which it is much easier to
syntax check than C or any of its derivatives (C++, Java etc.), thus
Pascal compilers can be smaller and faster.

It is quite possible to build a 'state machine' for Pascal in which,
in any particular construct of the language, there are a limited
number of legal states that you can transition to, and in fact, that
is exactly the way most Pascal compilers are written. (Having read
the source code to some 9 different Pascal compilers written for 6
different systems, I believe I am qualified to offer such an opinion.)

Such a capacity is impossible for C and C++. That makes compilers for
those languages much more complicated, bigger and slower.

> AFAIK static linking is always needed on programmes written for
> Windows because you can't assume that the C libraries will be
> available on the user's PC.

Actually, that is not true on both points. Most Microsoft Windows
applications use dynamic linking and you usually CAN assume the
libraries you need will be available on the user's PC. I'll explain
why.

If you write a program using anything that is referring to Microsoft
Visual C/C++, those libraries are included as standard components of
Microsoft Windows (because some parts of Windows are written using
Microsoft's C compiler, natch). Now, when you create an application
you're supposed to build an install for it that includes all necessary
components. Most Microsoft Windows-based compilers that I am aware of
(Visual Basic, Visual C, Delphi, etc.) do include either a rudimentary
installer that will at least set up the application and include
appropriate files, register necessary components include needed
registry keys and libraries, or they include a stripped-down version
of a third-party installer.

Visual Basic's default installer is itself written in Visual Basic
except for a small stub-loader written in Visual C to load some
libraries needed by the installer. Visual C's installer is, of
course, written in Visual C. Delphi uses a 'light' or 'personal'
version of Installshield. Those at least, are the ones I know of.

You may also purchase a number of third-party installers
(InstallShield, Wise) or obtain open source third-party installers
(Inno Setup) that will do the job and are essentially programmable
tools in their own right, sometimes requiring a degree in rocket
science to use them properly. The installers are supposed to check
for the presence of libraries and components on the system where the
application is to be installed, and to install missing ones as well as
upgrade older libraries as needed.

Most Microsoft Windows applications that use components or libraries
therefore are in fact dynamically bound to them at run time because of
the 'usual and customary practice' of installing the 'latest and
greatest' files when a program is installed.

This is one of the reasons why to install an application you can't
simply copy files over to a Windows 9x/2000/Me/NT/Xp system like you
could with DOS and Windows 3.1 applications, because of the use of
dynamically bound libraries. (Plus possibly registry keys and
application settings, another matter altogether.)

--
Paul Robinson "Above all else... We shall go on..."
"...And continue!"

0 new messages