home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Fish 'n' More 2
/
fishmore-publicdomainlibraryvol.ii1991xetec.iso
/
fish
/
languages
/
northc_384
/
mini-hello
/
readme
< prev
next >
Wrap
Text File
|
1990-08-30
|
6KB
|
133 lines
(c) 1990 S.Hawtin.
Permission is granted to copy this file provided
1) It is not used for commercial gain
2) This notice is included in all copies
3) Altered copies are marked as such
One complaint that is voiced about 'C' is that trivial programs are too
large. This opinion is usually held by those who have "played with" 'C'
and only every produced trivial programs, in this directory I explain how
to make smaller 'C' programs, and what you lose by doing so.
Before I can describe how to create small programs I must explain why
the simplest 'C' program, which is
main()
{
}
takes so much space.
The first thing to note is that every 'C' program consists of three
parts, the startup code, the programmers routines, and the 'C' library.
The startup code is a standard set of routines that are called when every
'C' program starts, these routines set up things so that the 'C' library
will work and calls the users main() routine in a standard way. The 'C'
library is a set of routines that the user may want to call, these range
from the very well used routines such as printf() to the extremely obscure
routines such as strpbrk().
The 'C' library will only add code if one of the other two parts
requires it, so for example the strstr() function is added to the
application only if it is called from the startup, which it isn't, or the
users code. For some routines the situation is more complicated, the
fputs() routine, for example, calls the fputc() routine, so if the startup
calls fputs() then both fputs() and fputc() are linked into the final
executable program from the 'C' library.
The normal 'C' startup code calls some routines in the 'C' library, on
real applications this makes little difference to the size of the final
code, because the users code probably calls all the routines that the
startup uses anyway. On trivial applications the chances are that the
routines the application calls are different from those that the startup
uses. For example the startup uses fputs() if the application calls
printf() then the final code must include both routines, even though they
do almost the same job, so the final program will be larger. So if the
hello world program is written as
#include <stdio.h>
main()
{fputs("Hello world\a\n",stdout);
}
then the executable code will be smaller, the routines that the startup
uses are
atexit() CloseLibrary() exit()
fclose() fflush() fputc()
fputs() free() ltoa()
malloc() OpenLibrary() strncpy()
_exit() _main()
so if you stick to this set you will reduce the size of your program.
This is all to the good, however since the empty program is a few
kilobytes long this is not the ultimate answer, we must reduce the size of
the startup code.
The startup code is the same for the vast majority of 'C' programs, the
programmer has to work hard to use a different startup routine. This
means that the startup must initialise the data structures for all the
possible library routines that the program can call, for example the
malloc() family of routines maintain a list of allocated memory chunks, so
that they can be freed when the program exits, this list must be
initialised just in case the program is going to call malloc(). There are
quite a few lists and data structures that must be set up.
The startup code is split over a number of routines, the "crt0.asm" file
contains most of the low level routines, these call the higher level
routines. The low level routines initialise the malloc() lists, the
floating point support, the Amiga library support, the low level file
handling, starting from the Workbench and the low level _exit() routine.
The high level routines deal with the "FILE" structures, the exit() and
atexit() routines, and the command line processing. Most of the space in
the high level routines deals with the command line processing, this is an
area that is often neglected, for example the command
example "Arg one in quotes" two three
has three arguments. Other languages, and even some 'C' compilers, will
treat this as six arguments.
So the reason why the empty program is so large is that it contains
support for all the obscure 'C' routines you could have used, even if you
don't. So the ultimate way to reduce the final size of your 'C' code is
to take out the support for the routines you are not going to use, start
with the "crt0.asm" file, and take out the calls that initialise the
structures you don't want. This is what I have done in this directory, I
have created "crt1.asm" a startup that sets up very little, and calls the
routine _main().
Of course if you want to use this trick to reduce the size of a program
you would take the following steps,
1) Get the program working with the normal startup.
2) Change the main() routine from
main(argc,argv)
int argc;
char **argv;
{
.
.
}
remove all the FILE references and change the function to
extern long _cmndlen;
extern char *_cmndstr;
extern long _fromWB;
_main()
{
.
.
}
3) Get a local copy of "crt1.asm" and remove the bits you don't need.
4) Edit your Makefile to use the local "crt1.o" rather than "clibs:crt0.o".
Once you have done all this you will learn a great deal about the guru, it
really is simpler to live with the larger programs.