On Sat, Jun 28, 2014 at 8:35 PM, Zbigniew <zbigniew2...@gmail.com> wrote:

> It was always a bit strange to me, that I had - well, I still have ;)
> - a few quite useful Pascal compilers for such little machine, like
> Commodore 64, and just one C compiler (Power C), which is cumbersome
> and hard to work with. C compiler - for the language being "closer to
> machine" than Pascal or BASIC - theoretically should be less
> resource-hungry (just like Forth compilers).

There are fundamental language differences to take into account.

Niklaus Wirth created Pascal as a teaching tool, for teaching
algorithm design.  It was originally intended to be "compiled" on
paper, with the teacher grading the quality of the student's
assignment.  In ISO standard Pascal, the last I knew, things like I/O
were undefined, because a program wouldn't *do* I/O.  When compiler
writers began creating compilers to generate executables from Pascal
code, they had to roll their own in areas like I/O, because it wasn't
defined in the language.  Pascal spread widely be4cause it was
relatively easy to learn to write, but became inherently non-portable
because of differences in implementations.

The C language was created by Dennis Ritchie at Bell Labs, largely
concurrently with the development of Unix by Ken Thompson and Brian
Kernighan.  C was intended to solve a specific problem.  Up till C
came about, systems software, like operating systems, was written in
the flavor of Assembler supported on the target machine.  The DEC
minicomputers used to host the development of C and Unix, for example,
used Macro-11, DEC's flavor of Assembler.  (DEC also had a specialized
language called BLISS intended for systems software.)  The problem
with Assembler was that while it provided the greatest possible
efficiency, it was hard to write and harder to maintain.  The
developer had to think with the machine's point of view, which was
very different from the problem to be solved. Ritchie was creating a
language intended to have the control constructs available in higher
level languages, but efficient enough that you didn't *have* to write
in Assembler to get adequate performance.  Another goal was that it be
portable, and relatively easy to bring up on a different machine.  He
wanted a language to make it easier and faster to write operating
systems.

Unix was intended to solve a similar problem.  Thompson and co-workers
were software developers, unhappy with the facilities provided by the
DEC systems on which they worked to support the task of software
development.  The had an old DEC mini that was essentially unused, and
could start from scratch, creating a new OS better suited for
developing software.  Early versions of Unix were written in Macro-11.
Around Unix v6, C became mature enough to be used, and most of Unix
was rewritten in C.  Only really low level code that interfaced with
the hardware was coded in Assembler.  The portability of C made it
possible to bring up Unix on systems that weren't DEC minis, and it
began to spread throughout AT&T.  (An early driver of the spread was
being able to use the vi screen editor when writing patent
applications, instead of the line editors available up till then.)

The earliest C compiler used in Unix "compiled" the C language
statements into Assembler, and then called as, the system assembler,
to generate the object code from the Assembler, and ld, the link
editor, to put the parts together into an executable the user could
run. It was possible to interrupt the compilation before as was
called, and hand optimize the Assembler code before continuing. It was
rather later that C compilers became sophisticated enough to comple
directly to object code.

Those early DEC minis had a 32K address space, so C had to be compiled
in a low resource environment.  But generating the *smallest*
executable wasn't the main goal.  There is always a tradeoff between
speed and code size.  The fastest possible code is in line, but the
more code that is in line, the larger the object file will be.  To
make code small, you isolate code that will be executed multiple times
as a function, and you call the function, but calling the function has
overhead and your code isn't as fast.  In addition, C encouraged the
development of libraries, where functions used in many programs could
be stored for reuse, and you passed the compiler a parameter telling
it where to look for libraries used by your program.  When you
compiled your code, and a function was encountered that was not in the
code you wrote, the linker would search the libraries passed for the
code than implemented that function, and include it in the executable.

Doing all that took resources,  The compiler had to have a temporary
file where the compiled output was stored, buffers in memory to hold
the code being compiled, and tables in memory to store information
about the code being compiled and what should occur.  The early DEC
systems  were virtual memory systems, so a 32K workspace wasn't an
insuperable imposition, because everything didn't have to be held in
memory.

On something like a C64, it *was* an imposition, because you had a 48K
workspace by default (unless you twiddled a memory management bit and
didn't map the BASIC interpreter into the 6510's address space), and
that memory was further fragmented by the memory mapping the C64
implemented.  (There was a 4K block of RAM between the 8K blocks
occupied by the KERNEL and BASIC ROMS, and a 1K work area at the
bottom of user memory with things like pointers and the cassette tape
I/O buffer.)  Forget virtual memory, when disk was a 1541 floppy drive
with a 300 baud serial interface. It was no surprise that the C
compiler for the C64 had limitations.  (IIRC, no support for unions.)

Turbo-C under MS-DOS faced similar hurdles, because DOS was not a
virtual memory system.  And using the GUI added ease but reduced
flexibility, as it largely limited you to what the defaults were as
implemented by the compiler.  To generate really small code, you had
to understand what took up space in the executable, and in some cases
write your own code which would replace the system library code with
something that took less space.  The advantage to C was that it could
potentially generate faster (albiet larger) code, and the code you
wrote could potentially be recompiled on a completely different
machine with a different architecture and still do the same thing.
(Writing truly portable code was an art form few really learned, and
the learning process generally involved trying to compile your code on
another machine, watching it die horribly, and making the fixes so it
would compile.)

C isn't magic.  There are things doable in C not easily doable in
other languages, but they don't happen automatically.  You must
understand the language, what it does, and how it does it, to make
them happen, and generating small object code is one of those places
were knowledge is critical.

> Z.
______
Dennis

------------------------------------------------------------------------------
Open source business process management suite built on Java and Eclipse
Turn processes into business applications with Bonita BPM Community Edition
Quickly connect people, data, and systems into organized workflows
Winner of BOSSIE, CODIE, OW2 and Gartner awards
http://p.sf.net/sfu/Bonitasoft
_______________________________________________
Freedos-user mailing list
Freedos-user@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/freedos-user

Reply via email to