Contents of the INSIDETC.DOC file
Inside Turbo C 2.0
(A discussion of Borland vs Microsoft C with a summary at the end of the
by: Victor Cummings
I've been programming in Turbo Pascal since version 3.0 and upgraded to
the 4.0, 5.0 and 5.5 versions. I am the type of programmer who dog ears
the manual of any compiler or assembler and then tries most of the verbs
out for a day or two prior to writing a program with it. This file is
intended for either the novice C programmer who knows Pascal, or the C
programmer who wishes to know some of the advantages and caveats of
coding in Turbo C 2.0. I have not yet upgraded to the C++ compiler, so
this may be a little out of date for those of you who have, but I'll do
that shortly. I have taken my time in doing this, because I own the
Turbo C 2.0 Runtime Library code, and I don't want to go to the expense
of having to upgrade this as well.
I've talked to several west coast C programmers who have switched to
Borland's Turbo Pascal since the 4.0 version, because they claim that
they can do the same programming, get a smaller code size and do it all
in record time. So why switch to C? I agree with them if of course they
are coding an application which will not need to be cross compiled to
run on the 6502, is not a communications application and does not need
to have an object model format and does not have to have firm control
over the heap.
I have also been scoffed at by some C programmers who think that my
understanding is limited because I choose sometimes to use Turbo Pascal
over C. Why bother with numerous warning errors, compile errors and
linker fixup errors if you don't have to whether you understand them or
not. I've learned Calculus, but I don't use it in the supermarket: I
use only arithmetic there.
Some of the functions that C has to offer I can code in Pascal with a
minimum of overhead expense, but there are some advantages and caveats.
Turbo Pascal is a remarkable product, and if you are coding for the IBM
PC stand alone or in some instances networked systems, I would stick to
it for most programs with several exceptions. Though dynamic memory
allocation is simple and fully functional in Turbo Pascal, you have
little control over the heap.
You may release the contents of the heap at any time in a Turbo Pascal
program, but you may not reallocate memory to DOS set by the $M compiler
directive at compile time. If you need finer control of the heap then
Turbo Pascal is not for your application.
I have written some interrupt handlers, driver interfaces and bitwise
functions and proceedures and can do assembler interfacing to Pascal, so
why I ask myself do I want to switch to C?
These are my four reasons:
1. Portability of C
2. Enhanced Machine Control of C
3. Wider use of C in professional coding for the IBM PC
Turbo C 2.0 vs Microsoft C
I've finished evaluating the Turbo C 2.0 compiler, and I'll share with
you some of my discoveries. I find it to be a nice product and worthy
of use for many applications with a few exceptions.
Turbo C 2.0 caveat #01: Turbo C and Microsoft C have different floating
point conventions. For this reason, it is difficult to link Turbo C
graphics routines to other languages such as Clipper. It is possible to
link Turbo C routines to programs in other languages written in other
languages such as clipper, but these routines may not include floating
point instructions or graphics routines in Turbo C which heavily rely
Turbo C 2.0 caveat #02: The Turbo C linker is faster but not as full
featured as Microsoft DOS linker. The manual lists several reasons why
the linker is limited, but the major reason is this: it contains no
overlay linker. Also the compiler offers no internal or external
overlay manager. It does have a family of spawn functions which do
work, but they are limited in their reporting to DOS and do not take
advantage of undocumented or cryptically documented DOS internal overlay
manager. DOS has a lot of undocumented functions and capabilities that
are reserved for use by Microsoft itself and this is one of them. These
features have been documented by experts in DOS and hackers alike. My
favorite of the experts is the Waite Group. They publish a great amount
of this information. With a little digging through my manuals I found
out that DOS fully supports internal overlays without using the EXEC DOS
function call, but since MASM does not have an internal overlay manager
which uses this capability, the MASM linker does not supply you with the
ability to do this. This feature is intended for use by Microsoft
compilers, and is therefore not documented in most DOS manuals. My DOS
3.2 manual contains it, but my 3.3 manual does not. The linker from the
3.3 DOS disk worked as stated in the DOS 3.2 manual. You may link
internal overlays by specifying their object modules by parenthesis:
This would link a program called database with three overlays: ADD,
EDIT and DELETE. This link does get accomplished and I have tried it,
but since no overlay manager exists, the program will crash and burn
when the overlay code is executed. This is either because the overlay
code is overlaying the root DATABASE or because the overlay code is not
returning. With a good symbolic debugger, some macho programming and
the DOS programmer's reference you could probably write your own overlay
manager by writing your own interrupt 63 (0x3F) handler. This would
enable you to code internal overlays in Turbo C 2.0 automatically up to
the size of your transfer media. Microsoft offers this for you already
without the macho programming.
Turbo C 2.0 caveat #03: The graphics library with Turbo C 2.0 is
proprietary and is not included with the Runtime Library. For this
reason I found it very hard to directly modify the EGA or VGA registers
by direct port addressing while the graphics library without crashing
the machine. I've gotten around that with a kludge. Since the Runtime
library does not contain the code for the graphics package, I had to
supply a kludge so that I could use assembler graphics routines in
harmony with Borland's graphics initialization routines. The kludge was
this: If you modify the graphics mode yourself within your own
routines, do not make a call to closegraph. Simply return to textmode
using your own code. I have no idea why this works, but it does. Since
it works, I won't fix it.
Turbo C 2.0 caveat #04: If you are currently using MASM, your CodeView
debugger will not be supported. You will be able to add assembly
interfaces, but you will not be able to debug them without SYMDEB or
Borland's debugger. You may have to switch to TASM or just make sure
you know what your own assembler code is doing before you interface.
Turbo C 2.0 caveat #05: If you are using some ASM code which you bought
or got from another programmer, make sure that the code uses assembler
instructions for the processor that you are using. If you are not using
the -1 compiler option to produce code for the 186/286 processor then
the Turbo C compiler will produce 8086/8088 instructions only for use on
XT computers. The compiler will not however check to see that this
convention is adhered to in any ASM code that you have assembled. The
linker will produce a fixup error message. These messages are
confusing, but can always be traced to either a mismatched variable size
in an assembler module or an 80286 instruction linked to 8086/8088 code.
If your assembly code is short, just reading the code may take you to
the error without going to a debugger. Perhaps you have taken a value
in the AX register from your assembler module and passed it to an
integer variable in your program. If you are passing a value from a 16
bit register to an integer variable in Turbo C, you'll get a clean
compile, but you must type cast the integer variable to get clean
Turbo C 2.0 caveat #06: If you are writing graphics routines for Turbo
C 2.0 do not waste your time trying to re-write the Borland's graphics
package EVEN IF YOU ARE an expert assembler programmer. I am not a bad
assembler programmer, and I am good at mathematics. I worked for about
three days to try to write a few routines that would out perform the
Borland's graphics routines. With the exception of my point plot
routine which runs about 2.4 times as fast and works only in EGA/VGA
modes the rest of the routines are slow by comparison. The main reason
I attempted benchmarks was that I was not sure at the time whether or
not I would be able to get additions to the graphics library to coexist
with it without being based on the library itself. I did not have the
ASM source for the library, so I wanted to bench mark it. The crux of
my advice is this: concentrate on adding routines that the graphics
library does not have and use the kludge mentioned above. You may need
a debugger to do this. The graphics routines in the package are already
good, so if you need a circle use their circle command. If however, you
need to put a PCX file on the screen, then try my kludge. Twenty
minutes with the techical support people in California offered me the
same advice, and three more days of playing convinced me.
What is nice about Turbo C?
I like the _Cdecl and _Pascal modifiers, because they enable my to write
objects which can be shared by Turbo Pascal easily. The Turbo C 2.0
manual tells you not to use the _Pascal modifiers unless you fully
understand them, but then does not fully explain them. With much sweat,
I have found that they are useful, but have not been explained as simply
as they could have been. Quite simply, in order to use these modifiers,
in your assembly code you must understand a few things about the calling
conventions. The following assumes that you have written or are using
assembly code that is written for the C calling model and are modifying
it for pascal calling conventions. You must make the following changes
to the assembly code. The best way to get some of this code is to buy
the Runtime Library.
1. Pascal calls reverse the order in which parameters are passed from
the stack. Just reverse the offsets from the BP on all these variables
passed to and from your C program. Here is an example used in a
assembler procedure to move a screen image.
; large parms c
;cX0 equ [bp+6] ; same variables in c calling convention.
;cY0 equ [bp+8]
;cIoffs equ [bp+10]
;cIseg equ [bp+12] ; note that the segment and offset remain
;cRule equ [bp+14] ; the same after reversing.
large parms pascal
pX0 equ [bp+14] ; x screen position
pY0 equ [bp+12] ; y screen position
pIoffs equ [bp+8] ; offset address of image
pIseg equ [bp+10] ; segment address of image
pRule equ [bp+6] ; xor, and etc.
Make sure that you type cast the variables either in your prototype
header or in your program.
2. Make sure that you also reverse the order of the segment and offset
of any pointers that you pass from the stack.
3. You must issue a RET n (where n is the total number of bytes of all
stack variables passed.) instruction at the end of your assembly
routine. Just add them up and annex that n value to the existing RET
4. Take the underbar from the symbol identifier in your assembly code:
_my_asm_proc far ; then becomes
5. Caveat: This feature is nice, but it does require that you have a
function prototype for each and every function which you use. Once you
have them for all of your existing functions in C, you can just start
using that -p compiler option. Be sure you have a _Cdecl modifier for
any function which you have not modified.
The pascal modifier will speed up your code, and I do use it whenever I
don't need a variable number of parameters and where speed and code size
is of the essence.
If you are going to write a program which heavily relies on overlays,
you should consider using Microsoft C or some other compiler that
supports them. Borland will in the future I'm sure if they haven't
already in the C++. I did the above study of the compiler, because I
have started to write a game program, and I want to make sure that Turbo
C could handle it before I lay down 50000 lines of code. If the code
and data size of your program do not exceed the 640K block then you need
not worry about this. Most game programs do not. If you are writing a
word processor or desk top publishing program this is a different story.
I encountered one problem which was the reentrancy problem with the
Borland's graphics closegraph function. I solved that problem by the
above mentioned kludge of removing the closegraph function which
heuristically relates to "...if that hurts don't do it." My conclusion
is that yes I can write a good game with Turbo C, and I give it the old
college try now. Since I don't have Microsoft C, I might have one bad
day when I have to use spawn to create an external overlay. I'm pleased
with what Borland gave me for the money I paid. If you need any
assistance with the topics that I have discussed here, or please feel
free to give me a call.
Victor E. Cummings
P.O. Box 12295
Baltimore, MD 21281