Contents of the SMALLEXE.TXT file
This text file explains how to create smaller standalone QuickBASIC
executables. Hopefully it will help others avoid some of the frustration
I encountered learning HOW to accomplish this! Two topics are discussed:
1. How to eliminate floating point emulation code, and
2. Other tricks and tips
I am the author of pEDIT, a shareware text editor written in QB 4.5. As
pEDIT grew larger and larger, it became necessary for me to look at ways
of reducing the size of the program. I considered 5 options:
1. Stick with QB and do - something
2. Go to BASIC7 which is supposed to generate smaller/faster code
3. Go to something like Crescent's PDQ which uses an alternate link
library to generate smaller EXEs
4. Wait for QB 5.0 or QBX or ??? from Microsoft
5. Rewrite pEDIT in 'C'
QB is a great product for the price but it is NOT known for generating
small programs! The smallest EXE under QB4.5 is something like 12-15k
bytes. This is due mainly to the HUGE amounts of object code linked in
after compiling. It turns out that Microsoft's BCOM libraries are not
(here's a 25-cent word) granular enough. This means that whenever you
link in a procedure you are probably getting the code for several other
procedures. Sometimes the added code is insignificant; sometimes it is
An example is the HEX$() function. Whenever you use HEX$() you are
linking in a library module named 'hexoct' which contains three entry
points: B$FBIN (there is no BIN$() function), B$FHEX (what you want) and
B$FOCT (for the OCT$() function). The 'hexoct' module is only 50H bytes
but you get the idea. Why have code for octal when you're doing hex?
I could not justify $300+ for BASIC7, especially not knowing how much
improvement I could expect. Besides, I don't have an extra 10MB of disk,
a need for ISAM, etc.
PDQ is useful mainly for things like small utilities. It does generate
very small executables (as little as 1-2k) but it is just TOO DIFFERENT
from QB to be useful for large programs. MANY standard (read as Micro-
soft) BASIC functions are not supported, requiring massive changes.
Who knows when/if there will be a new QB with an optimizing compiler,
better link library, etc. I hope there will be something like the QBX
included with BASIC7. I have a major upgrade planned for pEDIT in January
1991 and can't wait.
I hate 'C'.
There isn't much we can do about the granularity problem. We have no
control over what Microsoft puts in their link libraries or how many
different procedures there are in each module. We can do something about
eliminating unnecessary floating point code. This turned out to be easier
said than done(!) Things you wouldn't DREAM use floating point - do.
To see if your program contains the floating point code, generate a link
map and look for EMULATOR_TEXT and EMULATOR_CODE. In BCOM45 these modules
are 2430H and 0170H bytes, respectively. If this floating point support
is present and you don't need it, you're adding an incredible 9632 bytes
of code to your program.
Following is a list of BASIC functions/keywords with information on
each's use of floating point. Obviously you can't have any real variables
declared - VAR! or VAR#. Also just as obviously, you can't use any real
operators or any function which is explicitly for floating point - INT(),
What What to do
/ (division)Replace by \ (integer division); instead of PCT# =
100 * (A/B) use PCT& = (100& * A) \ B
TIMERReturns seconds since midnight (~18.2 ticks per sec-
ond); replace by a FUNCTION that reads the system
clock and returns ticks; see sample ReadTimer&()
INPUTCan input reals so must replace by a BASIC SUB or
FUNCTION that uses e.g. INKEY$
INPUT #Same as above; see LINE INPUT #
VAL()One of the biggest offenders, always uses emulation;
it is also quite large and slow; use a replacement
such as NuVal&() - available on this Forum - or my
ABS()Uses emulation only if the argument is a real
STR$()Uses emulation only if the argument is a real;
CAREFUL: the may be cases when the compiler can't
tell there won't be any floating point?; if so,
need IntToStr$(), the reverse of StrToInt&()
PRINT USINGUses emulation only if the print mask is for a real
number, e.g. "###.##"
READExpected because you can READ into a real variable;
however you might think QB would be smart enough to
scan the DATA and see if any is float? replace by a
DATA$ string and a FUNCTION to parse it; see sample
LINE INPUT #Makes no sense at all as can *ONLY* input a string!
must replace by some other method of INPUTing a
single line at a time; note that INPUT # and LINE
INPUT # are very slow in reading sequential ASCII
data; see sample SUB InputLine()
The archive contains the sample programs SMALLEXE.BAS and LARGEEXE.BAS.
SMALLEXE.BAS uses the mentioned InputLine(), ReadData$(), ReadTimer& and
StrToInt&() replacements for LINE INPUT #, DATA/READ, TIMER and VAL().
When compiled under QB 4.5 and linked with NOCOM+SMALLERR (see below),
the EXE sizes are 21088 and 33308 bytes, respectively.
I was able to reduce the size of PEDIT.EXE by 11,200 bytes. While this is
not a huge reduction every bit helps. It would be difficult to trim this
much by tweaking!
OTHER TIPS AND TRICKS
Other things can be done to reduce the EXE size. One easy way - which I
just rediscovered - is to link with NOCOM.OBJ. This object file is pro-
vided by Microsoft but was not included with QB 4.5. I found it mentioned
in the file BASAPP.TXT in this Forum. You can get NOCOM from Microsoft or
use the one included with previous versions of QB. Microsoft claims a
reduction of ~4k bytes; I saw about 3k. Note: NOCOM can be used only if
you program uses no serial communications.
Next, link with SMALLERR.OBJ (also from MS). This saves a few bytes by
eliminating the text of error messages; you will get an error number
only. You might want to do this after your program is debugged.
Minimize string usage. All assigned strings (as in VAR$ = "HELLO") have
to be stored somewhere. QB limits string space to a total of 64k so it is
easy to run out... the infamous "Out of string space" message. If pos-
sible, 'deassign' string variables to "" when you're done with them.
Eliminate the INTOLD86(X) routines in Microsoft's QB.BI. These are for
the old interrupt calls INT86() and INT86X(). The object code is in both
QB.QLB and QB.LIB. It turns out EVERYTHING in QB.LIB is included at link
time; you can again see it in the link map. If you don't need these old
INT86 routines, build new QB.QLB and QB.LIB files with just support for
CALL ABSOLUTE and CALL INTERRUPT(X). Following is a sample BAT file to do
this with QB 4.5:
rem Extract existing modules from QB LIBrary
lib qb.lib *absolute *intrpt ;
rem Build the new QuickLibrary w/o int86old
link /quick absolute+intrpt,qb.qlb,,bqlb45 ;
rem Build new LIBrary
lib qb.lib absolute+intrpt ;