From: qed@news.zocalo.com (Paul Hsieh)
Subject: *** WATCOM C/C++ FAQ *** (Preliminary)
Summary: WATCOM C/C++ FAQ
Newsgroups: rec.games.programmer,comp.os.msdos.programmer,alt.msdos.programmer
Date: 16 May 1996 11:17:27 GMT



               The WATCOM C/C++ Programmer's FAQ
 
 
WW        WW   AA   TTTTTTTT CCCC    OOOO      MM  MM    cccc  /
WW        WW  AAAA     TT   CC  CC  OO  OO    MMMMMMMM  cc    /
WW        WW AA  AA    TT  CC      OO    OO  MM MMMM MM  cccc/
 WW      WW  AA  AA    TT  CC      OO    OO  MM  MM  MM     /
 WW  WW  WW AA    AA   TT  CC      OO    OO MM   MM   MM   /
 WW WWWW WW AAAAAAAA   TT  CC      OO    OO MM   MM   MM  /  cccc   +   +
  WWWWWWWW AA      AA  TT   CC  CC  OO  OO  MM   MM   MM    cc     +++ +++
   WW  WW  AA      AA  TT    CCCC    OOOO   MM   MM   MM     cccc   +   +
 
                          Programmer's
 
 			  
     FFFFFFFFFFFFFFFFFF      AAAAA               QQQQQQQQQQQQQQ
     FFFFFFFFFFFFFFFFFF     AAAAAAA            QQQQQQQ     QQQQQQ
     FFFFFF                AAAAAAAAA          QQQQQQ         QQQQQQ 
     FFFFFF               AAAAAAAAAAA        QQQQQQQ         QQQQQQ 
     FFFFFFFFFFFFFF      AAAAAA AAAAAA       QQQQQQQ         QQQQQQQ
     FFFFFFFFFFFFFF     AAAAAA   AAAAAA      QQQQQQQ         QQQQQQQ
     FFFFFF            AAAAAA     AAAAAA     QQQQQQQ      QQ QQQQQQQ
     FFFFFF           AAAAAAAAAAAAAAAAAAA     QQQQQQQ   QQQQQQQQQQQ 
     FFFFFF          AAAAAAAAAAAAAAAAAAAAA     QQQQQQQQQQQQQQQQQQQ
     FFFFFF         AAAAAA           AAAAAA       QQQQQQQQQQQQQQQQQQQQ 
                                                               QQQQQQQQQQ
 
Written by Paul Hsieh
qed@chromatic.com
Revision 1.0
May 16, 1996

--------------------------------------------------------------------------- 


Introduction

Many/most of the questions dealt with here assume that you already own a
version of the WATCOM C/C++ compiler.  Ordering information is available
on WATCOM's world wide web site.

As my personal strengths are in DOS coding, I have slanted this FAQ at 
DOS programming using WATCOM C/C++.  If you are willing to contribute
information regarding Windows or OS/2 programming (other environments
probably don't really count since they would not satisfy the "F" part 
of FAQ) please send them to me and I will include it.  This FAQ mixes
advocation with technical information.  It has been written this way
because that is my natural style of writing.

--------------------------------------------------------------------------- 


List of questions:

Q. What is WATCOM C/C++?
Q. Where are WATCOM C/C++'s related web/ftp sites?
Q. Why is WATCOM C/C++ so popular?
Q. What's the syntax for ____?  How do I use the ____ tool?  How do I make
   the code generator do ____?
Q. Why do so many games use the DOS4GW.EXE DOS extender?
Q. What does WATCOM C/C++ come with?
Q. What libraries are available for WATCOM C/C++?
Q. How do I program for Direct X under WATCOM C/C++?
Q. Is the code WATCOM C/C++ produces the fastest/tightest?
Q. How does WATCOM C/C++ compare with other C compilers?
Q. How do I debug DOS4GW apps under Windows 95?
Q. How do I enable virtual memory for my DOS4GW application?
Q. Why doesn't WATCOM use "_asm" for inline assembly like Microsoft and
   Borland?  Afterall isn't that standard?
Q. Why does my code work only when I compile with debugging info on?
Q. What is FLAT memory model?  What is the advantage of a 32 bit compiler
   such as WATCOM C/C++ over 16 bit compilers and what are the differences?
   Will I be able to move my 16 bit DOS code straight over to 32 bit?
Q. I am getting this wierd error message ...
Q. I am having malloc troubles.  It seems that I am trashing the heap but
   I don't know how to debug it.
Q. How do I write directly to graphics memory?
Q. What is DPMI and what role does it play in using WATCOM C/C++?  How do
   I communicate between the 16 bit world and 32 bit world on my PC?
Q. What if I really need to compile a 16 bit model program?
Q. Why do WATCOM's results and Visual C++'s results differ on the same
   source code?  Why does WATCOM implement the default signedness of
   chars different from everyone else?
Q. Can I link external assembly files together with my C files?
Q. How do #pragma's work?  How do I do inline assembly language?
Q. How do I do compiled bitmaps?  How do I do on-the-fly generated code?
Q. How do I install a 32 bit interrupt vector?  How do I install a bimodal
   interrupt?
Q. Are there any other WATCOM C/C++ caveats?

--------------------------------------------------------------------------- 


Questions with answers.

Q. What is WATCOM C/C++?

A. WATCOM C/C++ is an Intel x86 based ANSI C++ and C compiler.  It
supports various target operating systems (namely 16 and 32 bit DOS, 16
and 32 bit Windows, OS/2, AutoCAD, QNX, Novell NLMs and others.)  Its most
notable and exercised strength is its 32 bit DOS based support.  WATCOM
has established its reputation as the makers of a world leading C compiler
and has been in business for about 10 years.  More information can be
gotten from their web pages.

---------------------------------------------------------------------------


Q. Where are WATCOM C/C++'s related web/ftp sites?

A. These are the URLs that I am aware of:

WATCOM's home page	
    http://www.watcom.com/
WATCOM's ftp site      	
    ftp://ftp.watcom.com/pub/bbs/
WATCOM's 10.x readme	
    http://www.watcom.com/c/readc10.html
KNUT's WATCOM C/C++ tutorial	
    http://www.oslonett.no/home/oruud/wat_tut.htm
Previous WATCOM C/C++ FAQ
    ftp://x2ftp.oulu.fi/pub/msdos/programming/watcom/watcom.07
List server for WATCOM users
    mailto:WATCOM-L@umdd.umd.edu 
         send a message to listserv@umdd.umd.edu with the subject:
         "SUBSCRIBE WATCOM-L John Doe" to subscribe.
Newsgroups
    news:alt.msdos.programmer
    news:comp.os.msdos.programmer
    news:rec.games.programmer

For tutorials on C/C++ (not specifically WATCOM) I have the following URLs:

C tutorials
    http://www.strath.ac.uk/CC/Courses/NewCcourse/ccourse.html
    http://www.iftech.com/classes/c/c0.htm
    ftp://x2ftp.oulu.fi/pub/msdos/programming/docs/teach-c.zip
C++ tutorial
    http://www.iftech.com/classes/cpp/cpp0.htm

---------------------------------------------------------------------------


Q. Why is WATCOM C/C++ so popular?

A. WATCOM C/C++ is a very good tool.  It was the first pure 32 bit C/C++ 
compiler available for x86 platforms.  It is a cross platform, high 
performance object code generator with no shortage of support tools.  It
is on these merits that WATCOM has sustained its popularity.

Somewhere around 1992-93, WATCOM decided to drop the price (to a mere $400 
Cdn vs. the old price of $1200 US) and started advertising more heavily in 
magazines such as BYTE and PC Magazine.  Around this time I was heavily 
advocating it (version 9.0) it in newsgroups such as "rec.games.programmer"  
as the premiere C compiler for high performance and reliability, making such 
bold statements as: "WATCOM C/C++ will produce code which is at *least* 
twice as fast as your current 16 bit compiler, and more typically around 
five times as fast" which was not stretching the truth as far as I knew it.  
Flame wars ensued where the focus was not only Borland and Microsoft, but 
WATCOM.  

Then a single program was introduced that brought immediate and serious 
attention to this compiler: DOOM.  What is this magical "DOS4GW" thing that 
makes DOOM so good?  Were the DOOM programmers serious when they said they 
used almost no assembly language?  What C compiler could they have possibly 
used that could pump that much game onto the screen?  Soon, more and more
games were made, hailing the telltale "DOS4GW" banner.  A few years later
PC Magazine ran a comparative study of a collection of C compilers.  They
hailed WATCOM C/C++ v9.5 for producing the fastest code (by a *wide* margin)
but critisized it for its klunky command line driven interface.

Since then many game companies switched and dozens of titles appeared with
the "DOS4GW" banner displayed proudly including:  Raptor, System Shock,
Descent, Magic Carpet, NASCAR Racing, Terminal Velocity etc.  32 bit was
finally becoming a reality on the PC, and it had nothing to do with
"Windows" or "OS/2".  But even IBM was getting smart.  Numerous OS/2
utilities and parts of the OS itself were compiled using WATCOM C/C++.

With version 10.0 WATCOM introduced an IDE.  With 10.5 it added an
assembler, while out sourcing the new and improved IDE to an award winning
third party developper.  With its licensing of MFC and ability to do ...
well just about anything, WATCOM has clearly set its sights on one goal:
To become the defacto standard C/C++ compiler for PCs. Even Microsoft
dares not ignore WATCOM C/C++; "Direct X" is compatible with WATCOM C/C++
(this was no doubt at the demand of the 3rd party BETA testers.)

---------------------------------------------------------------------------


Q. What's the syntax for ____?  How do I use the ____ tool?  How do I make
the code generator do ____?

A. The first place to look when trying to deal with general questions is
the online help.  In a DOS box you can access the help via:

WHELP help_file [topic_name]

If you've installed the compiler to use the CDROM, be sure to have the
WATCOM CDROM in the CDROM drive.  It takes a little digging but there is a
lot of online information available.

If you give no parameters on the, most of the tools will respond with
proper command line syntax.

Additionally, the file %WATCOM%\DOS4GW.DOC gives you information on 
configuring DOS4GW.EXE for certain systems and for using virtual memory
under DOS.

---------------------------------------------------------------------------


Q. Why do so many games use the DOS4GW.EXE DOS extender?

A. DOS4GW.EXE is the royalty free redistributable 32 bit DOS extender that
comes with WATCOM C/C++.  DOS4GW.EXE is made by "Tenberry Software"
(formerly Rational Systems) specifically for WATCOM.  Although alternative
DOS extenders with more/different features exist, users of WATCOM C/C++
for DOS programming (that is to say, game programmers) will tend to use
DOS4GW by default.  (It also has brand name recognition which may lead
some programmers to desire the telltale DOS4GW banner.)

---------------------------------------------------------------------------


Q. What does WATCOM C/C++ come with?

A. You can get a more complete description on the WATCOM web site, however
here are just a few things that are included:

  - 32 and 16 bit compilers, with standard libraries and DOS4GW.EXE.
  - Additional DOS graphics and x86 specific libraries.
  - All flavours of Windows programming including 16 and 32 bit MFC support
    as well as Win32.
  - Numerous Windows development tools (dialogue editors and so on.)
  - Support for Dos extenders, OS/2, QNX, and AutoCAD.
  - IDE: Editor, Debugger, Linker, Execution Sampler/Profiler, Make, Touch.
  - Online documentation and sample code.

---------------------------------------------------------------------------


Q. What libraries are available for WATCOM C/C++?

A. I don't have a comprehensive list, but I know that Varmint's Audio
Tools, Fast Graph, YackIcons, WordUp Graphics Toolkit and Microsoft's 
Direct X based Games SDK are notable libraries that come in WATCOM C/C++ 
friendly flavors.  In their latest versions, WATCOM has really gone out of 
their way to make themselves more compatible with Visual C++, which leads 
me to believe that many libraries out there which have been compiled for 
Visual C++ will also work with WATCOM C/C++.  Needless to say there is no 
shortage of libraries out there that support WATCOM C/C++.  The WATCOM web 
site lists numerous 3rd party developers that are supporting their C/C++ 
compiler.

Here's a list of some stuff on the x2ftp.oulu.fi ftp site:

Graphics libraries

WGT Watcom 	ftp://x2ftp.oulu.fi/pub/msdos/programming/wgt51.zip 
Xlib Watcom 	ftp://x2ftp.oulu.fi/pub/msdos/programming/xlib/xlib06p2.zip 
Watcom ModeX	ftp://x2ftp.oulu.fi/pub/msdos/programming/watcom/w_modex.zip
 
Audio libraries

VAT Watcom      ftp://x2ftp.oulu.fi/pub/msdos/programming/mxlibs/vatpm061.zip 
SMIX Watcom     ftp://x2ftp.oulu.fi/pub/msdos/programming/mxlibs/smixw125.zip 
DSIK Watcom     ftp://x2ftp.oulu.fi/pub/msdos/programming/mxlibs/dsik205.zip 

---------------------------------------------------------------------------


Q. How do I program for Direct X under WATCOM C/C++?

A. I haven't the slightest clue, and would appreciate any info anybody has
regarding this.  The following conversation occurred on the USENET recently
however:

  >How well does the Games SDK work with Watcom? If well, how many
  >trials did it take to get the 'magic options' set up right?

  Works well, so far. I did have to use the windows.h file supplied with
  the Games SDK, and that was hidden somewhere under the SAMPLES
  subdirectory. I also had to define a couple of macros to get the samples
  to compile. The whole thing took about 4 hours.

---------------------------------------------------------------------------


Q. Is the code WATCOM C/C++ produces the fastest/tightest?

A. The WATCOM C/C++ compiler is generally regarded as among the best in
terms of code generation.  For example, it produced significantly better
code than any 16 bit compiler.  In an article in PC Magazine a few years
back, benchmarks indicated WATCOM C/C++ version 9.5 had the tightest and
fastest code among such compilers as Visual C++, Borland C/C++, Metaware
Hi C, Zortech and Symantec (by a wide margin).  WATCOM's compilers have
generally lead in the performance category in all brands and versions of
their compilers starting with version 7.x, however among the more modern
compilers it appears as though both "djgpp" and "Visual C++ 4.x" produce
pure C code compilation which is as good (if not slightly better) than
WATCOM's.

However, among the reasons for chosing WATCOM for high performance code
generation is also its ability to use inline assembly language, the
disassembly tool and its ability to collect accurate performance profiling
information.  These tools are an indespensible part of the a "pedal to the
metal" coder.

---------------------------------------------------------------------------


Q. How does WATCOM C/C++ compare with other C compilers?

A. WATCOM C/C++'s biggest strengths right now are the performance tools
and its ability to do cross-platform development.  With WATCOM the concept
of a single project targetting multiple platforms is a practically
realizable goal.  

By comparison, Microsoft is currently only supporting VC++ 4.x which can
create targets for exactly one platform:  Win32.  That means Windows (Win
32s is required for Win 3.x users.)  16 bit code is not an option.  For
that you need to go back to VC++ 1.5, and I'm not sure how you can get
your hands on that.  For 32 bit DOS extenders you need to go to VC++ 2.x.
That's an aweful number of C compilers that you have to get your hands on,
to do less than the job of WATCOM C/C++ alone.  The code generator for
version 4.x compares favorably against WATCOM's, but the lack of reliable
performance tools and the klunky out-dated method of inline assembly keeps
VC++ from being the performance compiler of choice.

Borland is looking straight into the abyss these days.  I am not very
familliar with their most recent products, but their strength has always
been their IDE and compile speed.  But the latest WATCOM C/C++ compilers
have closed these gaps considerably.  Borland attempted to diverge from
MFC with "OWL".  They also stopped support for DOS for a brief period.
These mistakes have cost Borland valuable time and their compiler
technology has suffered as a result.  They themselves have practically
admitted this and have thrown their efforts behind "Delphi" (a pascal-like
language.)

DJGPP beats all these compilers in two places: code generation and price.
(It appears to produce the tightest code, and costs $0.)  However, it falls
flat on its face in terms of platform support, compile speed and interface.
DJGPP is unlikely to ever support Windows and has only recently been robust
enough to produce targets that work under both DOS and Windows DOS boxes.
The support is there through the internet, but you have to be a real
propeller head (even more so than with WATCOM C/C++) to get it working, let
alone understand it.

I haven't heard so much as a peep from Metaware or Symantec these days.  Its
likely that in the face of VC++ these compilers have simply crumbled.  Indeed
its hard to see how any other compiler besides WATCOM C/C++ will survive
Microsoft's latest product monopoly maneuver.

---------------------------------------------------------------------------


Q. How do I debug DOS4GW apps under Windows 95?

A. I have not verified this myself, but Eric Kenslow posted a USENET message 
on rec.games.programmer to the effect that it could be done with WATCOM C/C++ 
10.6 as follows:

  Give this a try- I've been doing this with Watcom 10.5 under NT for a
  while now:

  1. Start 2 command prompts
  2. In prompt #1 type 'vdmserv -trap=rsi'
  3. In prompt #2 type 'wd -trap=vdm <executable-name>'

  The debugger should connect to the server in the other window and you
  can debug.

  /* Eric Kenslow
   * Student of Software Engineering, Oregon Institute of Technology
   * kenslowe@mail.oit.osshe.edu
   * http://www.oit.osshe.edu/~kenslowe (Senior Project & Resume Online)
   */

This is essentially the same procedure used for remote debugging over a
serial cable.  Gothmog <steiner@aghl.ruhr-uni-bochum.de> indicates that
you should use 'winserv -trap=rsi' for Window 95.  Others have posted,
confirming the fact that it cannot be started from the IDE, but instead 
must be done manually by opening two windows and starting the commands as 
mentioned above.

---------------------------------------------------------------------------


Q. How do I enable virtual memory for my DOS4GW application?

A. This and other DOS4GW specific questions are answered explicitely in
the file %WATCOM%\DOS4GW.DOC.

---------------------------------------------------------------------------


Q. Why doesn't WATCOM use "_asm" for inline assembly like Microsoft and
Borland?  Afterall isn't that standard?

A. Well, first off that most definately is *not* standard (as in ISO or
ANSI.)  Since the Microsoft/Borland _asm construct falls outside the ANSI
standard, it promotes the generation of C sources which are not portable.
WATCOM instead uses the ANSI sanctioned "#pragma" directive.  (See
discussion latter for why WATCOM's method is intrinsically more portable
than the _asm method.)  DJGPP also uses #pragma.  There is a file
"ASM.TXT" on the WATCOM web site which explains their reasoning more
fully.

---------------------------------------------------------------------------


Q. Why does my code work only when I compile with debugging info on?

A. Dom Laflamme asked this question on the USENET newsgroup 
   "rec.games.programmer" and I gave the following response:

Dom Laflamme wrote:
> Hi,
>         I've been coding a game engine for the passed 3 months. It works 
> fine and it's fast. Execept that when I turn the "Debugging Info" off in 
> Watcom, _nothing_ works, it just crashes. Since I cant debug the thing 
> properly because of lack of debuging info, I face a truly problematic 
> situation!

There is a big difference in the code generated by using the /d2 debug 
switch and no debugging.  /d1 is supposed to be nearly identical to using 
no debugging but has significantly less deugging information.  WATCOM's 
optimizations are *NOT* broken as someone else posted.  But they are truly 
aggressive.

WATCOM recommends setting: /otexan, and each switch (t, e, x, a, and n) is
sufficiently documented in the online help.  I'm guessing that you have these
setting all on since "it's fast".  This recommendation is based on the
assumption that you are writing correct ANSI-C and that you are not stepping
outside the bounds to the point of breaking one of WATCOM's optimization
strategies.

As a simple test, trying setting all the optimization switches off (as well
as the debugging switch off.)  If your engine starts working again, then
turn the optimization switches back on one at a time until your engine breaks
again.  Keeping in mind that that "a" switch (assume no aliasing) is the only
one in which correctly written (but really brain dead) ANSI C can fail to
execute.

Once you have isolated the switch, read the documentation on the switch very
carefully.  Try to isolate the problem area and disassemble the code with
each optimization switch.  Once you see the difference, you should be able to
figure it out.

You problem is likely one of three things:  (1) Simple mistake, like
dereferencing a bad pointer, or accessing outside the bounds of an array,
(2) You are misunderstanding the meaning of the "volatile" ANSI C keyword
and hence are misusing it, or not using it (the most likely) when you
should. (3) You are aliasing pointers to non-disjoint structures and WATCOM
is reordering an inner loop in too aggressive a manner (you will have to
either recode or remove the "a" switch entirely.)

I have seen all three cases in my own work and in the work of others.  I
found that using WATCOM is an exercise in "re-learning" how ANSI C really
works.

---------------------------------------------------------------------------


Q. What is FLAT memory model?  What is the advantage of a 32 bit compiler
such as WATCOM C/C++ over 16 bit compilers and what are the differences?
Will I be able to move my 16 bit DOS code straight over to 32 bit?

A. WATCOM can compile for either 16 bit or 32 bit.  The compilers are
named wcc/wcl and wcc386/wcl386 respectively for 16 bit and 32 bit
compiliation.  Every DOS programming model under the sun is implemented
including TINY, SMALL, COMPACT, MEDIUM, LARGE, HUGE (the 16 bit models) as
well as FLAT and LARGE32 (the 32 bit models).

WATCOM C/C++'s default 32 bit DOS memory model is FLAT memory model.  FLAT
memory model is an analogue of TINY model for 32 bit programs.  ES and DS
are set to the same selector which points at the base of memory and maps
all 4GB of address space.  CS is a selector that points to all of memory
like DS and ES, but has the execution attribute set, meaning that it
cannot be written to directly.  SS is set to a special stack segment to
make stack overflow easier to detect.  This set up allows you to, in
nearly all situtations, ignore segment/selector registers completely.  FS
and GS are available for applications to use as they see fit and by
default are set to 0.  (Hint:  Be sure to check the values of these
selectors whenever you are debugging a failure in your code.  These
selectors may change as a result of ill-behaved interrupt vector calls,
and hence may need to be saved and restored properly (see the #pragma
discussions elsewhere in this FAQ))

Unless you are dealing with interfacing to external 16 bit resources (such
as APIs implemented through interrupts) you never need to deal with 64K
segment limits, or strange keywords like FAR, NEAR or MK_FP.  Pointers and
int's are both 32 bit, and while its not advisable you can cast between
the two and still be portable to most platforms (16 bit x86 environments
and 64 bit DEC Alpha environments being the most notable exceptions.)

The extra bandwidth/precision you get for using a 32 bit coding model over
a 16 bit one speaks for itself.  32 bit instructions executed from 3s bit
segments do not need instruction overrides.  Beyond that only TINY and
SMALL models (from the 16 bit model choices) compare with the low overhead
for context switches.  That is to say, the only 16 bit models that
similarly don't require selector loads for new data pointers or function
calls are restricted to 64K of data and/or code.

Familliar DOS/BIOS data areas such as 0A000:0000 and 004f:0000 have been
mapped in the most natural way:  16*segment+offset.  So VGA space is now
at _FLAT:0x0A0000 and the standard BIOS area is now at _FLAT:0x04F0.  But
this mapping doesn't necessarily hold true for the rest of system memory.
This is actually a good thing since it allows for linearly mapped graphics
cards to have their address range placed at a convenient place, namely the
end of your conventional memory.

(It is important to note that the construct MK_FP(0xA000,0); doesn't have
the same meaning and will *NOT* correctly map the screen to a usable
pointer.  Use (char *)(0x0A0000) as just described.)

This sudden ease of implmentation for everything is actually likely to
make the job of porting from 16 bit DOS quite involved for many
applications.  This porting procedure would mostly be an exercise in
*undoing* all the 16 bit nonsense that was being done previously.

---------------------------------------------------------------------------


Q. I am getting this wierd error message ...

A. Lets go through some of the more common ones:

(1) When I run my program I get something like:

    DOS/4GW Protected Mode Run-time  Version 1.97
    Copyright (c) Rational Systems, Inc. 1990-1994
    DOS/4GW error (2001): exception 0Eh (page fault) at 237:825A401F
    TSF32: prev_tsf32 5290
    SS       23F DS       23F ES       23F FS         0 GS        87
    EAX FFFFFFFF EBX 8244A380 ECX        0 EDX        0
    ESI 824493A1 EDI 8244939C EBP 8244A374 ESP 8244A370
    CS:IP  237:825A401F ID 0E COD        6 FLG    10202
    CS=  237, USE32, page granular, limit FFFFFFFF, base        0, acc CFFB
    SS=  23F, USE32, page granular, limit FFFFFFFF, base        0, acc CFF3
    DS=  23F, USE32, page granular, limit FFFFFFFF, base        0, acc CFF3
    ES=  23F, USE32, page granular, limit FFFFFFFF, base        0, acc CFF3
    FS=    0, USE16, byte granular, limit        0, base        0, acc  0
    GS=   87, USE16, byte granular, limit     FFFF, base    18DD0, acc F3
    CR0: unavailable
    Crash address (unrelocated) = 1:0000001F

This means that you have an error in your program.  If the address given
in the last like looks like 1:0000????  (basically selector 1 and a
reasonably small sized offset) then chances are you can run this under the
debugger and have the address of your error shown to you.  If even the
address looks like its off in the weeds, remember that WATCOM's debugger
allows you to crawl up the execution stack to see how the crash was
arrived at.

Nine times out of ten you are simply dereferencing memory you shouldn't be
(past end of an array, stuffing a pointer without first mallocing it,
inadvertantly corrupting a pointer that you use later.)

(2) You type:

    wcl386 /l=dos4g hello.c

and get back:

    WATCOM Linker Version 10.6
    Copyright by WATCOM International Corp. 1985, 1996. All rights
    reserved.
    WATCOM is a trademark of WATCOM International Corp.
    Warning(1107): file __WCL__.LNK: line(2): undefined system name: dos4g
    loading object files
    searching libraries
    Error(3002): ** internal ** - format not decided
    Error: Linker returned a bad status

This means that when you installed WATCOM C/C++ you did not select 32-bit
DOS target.  You can run the installation procedure again to do an 
incremental install of 32 bit DOS compiler support.

---------------------------------------------------------------------------


Q. I am having malloc troubles.  It seems that I am trashing the heap but
   I don't know how to debug it.

A. Someone on rec.games.programmer asked this question and I gave this
as the response:

Apparently somewhere in version 10.0 or 10.5, WATCOM had a problem with 
mallocing that has been fixed in a subsequent build.  It is likely that a 
patch for it exists on their WWW site.

Nevertheless, I believe that bug was an extremely obscure one with the
"free" command and is unlikely to be your problem.  Dealing with a trashed
heap is difficult with any compiler, but WATCOM makes it particularly
challenging because of its "frugal" heap memory tracking system.  If you
do a little debugging/reverse engineering, you will see that a WATCOM
memory allocation tracks the size in the int (signed long) just before
the actual allocation itself.  So (ptr=(int *)malloc(100))[-1] should be
100.  The malloc/free functions use this and this alone to track the heap
so if you are trashing memory, especially these sizes, you will start
dying really soon.

I found that the WATCOM debugger is particularly good at tracking down
precisely this sort of problem.  Allow me to tell you a story:

Once upon a time I had a memory corruption in a large convoluted program I
was writing.  So I started debugging by putting a wrapper around the
"malloc" and "free" functions that added an additional size to test the
validity of each malloced size against when I use it (which I put on the
*other* side of the allocation.)  I put a test in the place where my program
was accessing it and GP faulting.  I simply output a message indicating that
the memory was trashed.  Using the debugger I put a break point on the error
message printer.  Then I used the "reverse execution" feature to get me back
to the failed memory size comparision and noted the machine address of the
WATCOM size pointer.  Then I reset the program and put a breakpoint on
access to that memory address.  It turns out that my program legally
accessed it several times (on the order of a thousand.)  So I used the
breakpoint "counter" to help me zero in (essentially a binary search) on the
number many times this memory was accessed before the crash occurs.  By
setting the counter appropriately, I found the code which was pounding on
the size and rectified it.  Total time spent was about 1.5 hours which is
not bad for a bug of this complexity (most of the time was spent on other
desparate attempts to find the bug *before* diving in and trying the above
procedure, which took < 10 mins.)

I can't praise the WATCOM debugger enough for enabling me to do the above
procedure.  In particular, the reverse execution feature gives me
unparalleled power (with the exception of Soft-ICE, which of course, gives
you much more power) for determining my context.  Mixed assembly and source
level debugging allowed me to reverse engineer WATCOM's malloc method
lickedy split.

BTW, the bug in my program was simple.  I was accessing a pointer before
malloc-ing it.

---------------------------------------------------------------------------


Q. How do I write directly to graphics memory?

A. As mentioned above, the base of VGA memory is mapped at 0x0A0000.  The
ports can be accessed via the outp() function, so even setting up Mode X
is no big deal.  CGA and EGA are no more challenge than VGA.

SVGA modes have their own special problems.  The examples in Ferraro's
book on VGA's and SVGA's can be easily adapted to WATCOM C/C++, even in
pure C, with the exception of the VESA SVGA stuff.  Revision 1.2 of the
VESA SVGA interface (the interface most widely supported by SVGA's out
there) requires a 16 bit memory allocation for a data buffer and a 16 bit
call or interrupt to the "Bank Switch" procedure (my own investigations
lead me to find that the WinPtr call was not reliable on many graphics
cards and thus I stuck with the interrupt).  These are both achieved by
using DPMI which is discussed elsewhere in this FAQ.  Revision 2.0 of the
VESA SVGA interface has a purely 32 bit interface and also allows the
option of mapping the entire frame buffer to a single contiguous linear
memory range.  The VESA SVGA specs are available at:

ftp://x2ftp.oulu.fi/pub/msdos/programming/specs/vesasp12.zip and
ftp://x2ftp.oulu.fi/pub/msdos/programming/specs/vbe20.zip

If you require linear memory access to SVGA, then your choices are:  (1) use 
a VESA 2.0 interface (the easiest way), (2) Map in the graphics controller's 
physical memory yourself (the hardest way), or (3) Use a more powerful DOS 
extender (than DOS4GW) that supports the DPMI phys to linear map function
(the expensive way, see next question for more information.)

Programming a graphics controller to use its specific functions requires
getting specifications for the graphics controller themselves.

---------------------------------------------------------------------------


Q. What is DPMI and what role does it play in using WATCOM C/C++?  How do
I communicate between the 16 bit world and 32 bit world on my PC?

A. DPMI stands for "DOS Protected Mode Interface" and was dreamed up by
Intel and Microsoft.  It was a method for extending DOS's functionality
for supporting 32 bit programming at the lowest possible level.  Windows
is an example of a program which implements and leverages the DPMI
interface to enable "Enhanced Mode" and 32 bit DOS Extended applications
to run under DOS boxes.  (QDPMI, CSWDPMI and DOS4GW itself are other
examples.)

For most purposes DPMI essentially is an API for setting up 32 bit
selectors, and call gates between 16 and 32 bit execution segments.  A
version 0.90 (the one used by Windows) specification is available at:

ftp://x2ftp.oulu.fi/pub/msdos/programming/specs/dpmispec.arj

Among its most common uses are:  calling a 16 bit interrupt which takes a
16 bit segmented address for a data buffer (ordinarily DOS4GW and/or
WATCOM's heap manager will not "malloc" from DOS memory, so it essentially
goes wasted.)  These are both required for supporting VESA SVGA 1.2.  You
may notice that among the many messages printed on DOOM's fake "DOOM OS"
init screen is a mention of DPMI.  The programmers at "id" probably wrote
their own memory manager which uses conventional memory in addition to
regular heap memory.

The major short coming of DOS4GW is that it is an incomplete
implementation of DPMI.  The WATCOM C/C++ users's guide describes what
DPMI functions *are* implemented in the "INTERRUPT 31H DPMI Functions"
chapter.  DOS4GW even steps outside of the bounds in the sense that
unsupported functions do not simply return with the carry flag set
indicating an error (even though it has not completed the DPMI function.)
Forunately the latest DOS4GW implements both the DOS alloc function and
the simulated DOS interrupt call, which are sufficient for setting up
rudimentary 16 bit communication.  If another DPMI manager is present,
however, DOS4GW will not set up its own DPMI server.  (I shelled out $150
for the CauseWay DOS Extender which is far more robust and feature rich.)

So how does one actually coordinate 16 and 32 bit components together?
Allow me to explain one method.  All 32 bit DOS executables are bound with
a 16 bit kick-start program.  This kick-start program is, by default,
named WSTUB.EXE and is located in the %WATCOM%\BINB directory.  Obviously
you can change the contents of this file to anything you like (you can
probably do this without mucking with %WATCOM%\BINB\WSTUB.EXE directly,
but rather using the WBIND command, but I have not investigated this
fully.)

The 16 bit source code for WSTUB is also supplied that makes the
kickstarting procedure fairly clear (starting with version 9.5, WATCOM
included both that 16 and 32 bit versions of their compiler in the same
package.)  It basically parses the command line arguments and passes
control to DOS4GW with itself as the first parameter followed by the rest
of the regular parameters.  You can write all your 16 bit components in
the stub, passing critical pointer values as command line parameters to
the 32 bit portion.  The pointers could point to anything, including 16
bit function entry point addresses and data areas.  The 32 portion would
do the simple math to convert the pointers and can pass control back to
the 16 bit stub functions using the DPMI 16 bit function call simulation
call.  Voila!

The reason I've described the above procedure is that I've seen others take
a less savory approach that I'd just as soon see avoided in the future.  In
at least one sound library I noticed that the implementer wrote a 16 bit
TSR that had to be executed beforehand.  Clearly, an unsanctioned or
unreliable method of communication between the 16bit TSR and 32bit library
was being used.  Using the stub method is much cleaner.

Personally, I've modified WSTUB.EXE in minor ways, but in all honesty, I
have to admit that I have not tried the above procedure myself.
Nevertheless, I cannot see any other reason WATCOM would expose the 16 bit
source for WSTUB.EXE.  If somebody ever implements (or has already done
so) this idea successfully, I'd like to know about it.

---------------------------------------------------------------------------


Q. What if I really need to compile a 16 bit model program?

A. Starting with version 9.5, WATCOM includes both the 16 and 32 bit
compilers in a single package.  The 16 bit compiler executables are
wcl.exe and wcc.exe, while the 32 bit compilers are wcl386.exe and
wcc386.exe.  It should just be a matter of changing your makefile or
flipping an IDE switch.

---------------------------------------------------------------------------


Q. Why do WATCOM's results and Visual C++'s results differ on the same
source code?  Why does WATCOM implement the default signedness of chars
different from everyone else?

A. A list of these differences can be found in the online help.  To get
around the signedness default be sure to pass a "/j" on the command line.
WATCOM's "wmake" utility parses a makefile format that is entirely different
from Microsoft's.  WATCOM decided to mimick UNIX as closely as possible, 
while Microsoft went ahead and made their own standard.  In general, 
WATCOM's C/C++ compilers tend to be more stable, however one notable 
exception was the initial release of version 10.0.  But WATCOM had patches 
available in a couple months which fixed its most outstanding problems.  
Relatively speaking, WATCOM's compiler is fairly robust and more ANSI 
compliant than Visual C++ which can explain certain discrepencies.

---------------------------------------------------------------------------


Q. Can I link external assembly files together with my C files?

A. WATCOM's linker can accept .OBJ files in its own format or in the
standard intel format so using a separate assembler should not cause any
extra unneccessary complications.  Earlier versions (9.0) of the compiler
required the use of the "WOMP" utility to convert object formats.  Starting
with version 10.x, WATCOM C/C++ also comes with an external assembler called
"WASM".  However about the most praiseworthy comment I've heard about it was
something along the lines of "when I wrote everything from scratch and
followed all its rules, WASM seemed to be able to do the job."  Basically, I
don't believe WATCOM implemented many of the common, but superfluous
assembler features of MASM or TASM which a lot of people rely on and hence
were complaining about.

---------------------------------------------------------------------------


Q. How do #pragma's work?  How do I do inline assembly language?

A. WATCOM's #pragma command is generally used as an alternative way for
defining C/C++ function generation properties.  Examples:

1.  If you know that the parameters for a function are available in
certain x86 registers then you can assign which go where *explicitely*.

2.  If you know that at link time you will need the exported function
names to be mangled is some nondefault way then you can deal with that in
a #pragma.

3.  If you want to generate inline assembly then you can do so as actual
assembly text or opcode bytes.  You give a function prototype and then
declare its content using the #pragma aux directive.

This system for dealing with inline assembly is very powerful as it allows
you to explicitely declare your register usage, so that your C and
assembly stich together perfectly.  A similar mechanism is also available
for DJGPP, but surprisingly, Visual C++ and Borland's "_asm" method is not
nearly as powerful.  With the "_asm" method it is recommended that you
look at the disassembly (you need to generate a .COD file in Visual C++)
of your surrounding source C to know what registers are available to use,
or simply do not modify any registers at all.  This makes inline assembly
coding tedious and difficult to maintain.

In contrast, the WATCOM method requires that you abstract your inline
assembly to have a regular C-function prototype which aids in portability
to non-x86 platforms.  A word of warning; inline assembly functions
declared with #pragma aux are not externed and hence behave like regular
C++ "inline" or "static" functions.  The typical method of dealing with
multiple C files using the same inline function is to define it in a local
include file common to your C files.  In this vein I think of #pragma's as
type checked macros, rather than functions.

Here's an example of the power of #pragma inline assembly for 32 bit FLAT
memory model.  Suppose we wish to implement the following:

  static void DWORDCopy(char *Source, char *Destination, int Length) 
  {
      for(;Length;Length--) 
      {
          *Source++=*Destination++;
      }
  }

in tight (i.e., small) assembly.  Using the WATCOM disassembly will show
you that the above is *not* compiled to a "rep movsd" no matter what
compiler settings you use.  The functionally equivalent inline pragma is
implemented as follows:

  void DWORDCopy(char *Source, char *Destination, int Length);
  #pragma aux DWORDCopy = " rep movsd " parm [ESI] [EDI] [ECX]\
  modify [ESI EDI ECX];

The above function will to copy a packed array of 32 bit quantities from a
source pointer to a destination pointer using the "rep movsd" x86 assembly
construct.  The source and destination parameters are put into ESI and
EDI, with the length in ECX which is exactly what "rep movsd" requires for
priming.  In addition movsd requires that es and ds are set up, but that
is all take care of by the FLAT model start up code.  To implement this
same thing for Borland C++ or Visual C++ you need additional priming code
to transfer the source and destination parameters to the correct
registers.  Finally, the C-compiler needs to know what registers were
modified by the inline #pragma so that it can figure out what registers
are available to the surrounding C-code.  This cuts down on unnecessary
save and restores of registers that is generally required to safely
implement an inline "_asm".

Typically, the meat of the code appears in the double quotes, and is
several lines long, however opcodes can also be entered directly as bytes
as well.  Remember that ANSI C constants strings can be broken up in
sequence, and that lines can be stitched together with a "\" at the end.
#pragma's have to be declared on one line, so longer inline assembly
language sequences typically look more like:

  void SetMode13(void);
  #pragma aux SetMode13 = 	\
  "	mov ax,13h	"	\
  "	int 10h		"	\
  modify [ax];

(My point above is that this #pragma statement is equivalent to:
  #pragma aux SetMode13 = " mov ax,13h  int 10h " modify [ax];)

Why would you ever want to enter opcodes?  Well, intel has a habit of
not documenting their mneumonics:

  unsigned int RDTSC(void *);
  #pragma aux RDTSC =   \
  0x0f 0x31 /* RDTSC */ \
  " mov [esi],eax   "   \
  " mov [esi+4],edx "   \
  parm [esi] modify [eax edx] value [eax];

(Although the WATCOM C/C++ compiler is actually aware of the rdtsc 
instruction, it comes back with a error about the CPU setting when I try
to use it.)

More detailed information can be found in the online help.

---------------------------------------------------------------------------


Q. How do I do compiled bitmaps?  How do I do on-the-fly generated code?

A. Its no big deal really.  Remember that CS, DS and ES are mapped to the
same physical space, so if you malloc some space, fill it with 32 bit
instructions (note that the opcodes between 16 and 32 bit do not translate
directly) cast it to a function pointer (be especially careful with any
parameters passed) and call it.

Modifying existing code (realizing of course that you take your life in
your own hands when you do this) is also possible.  Cast a function
pointer to a regular data pointer ((char *) is probably the only
appropriate pointer type) modify the data function code as if it were just
an array of opcodes and operhands, then call the function.

Unfortunately, it looks like the compiler can do something really odd.  If
you assign the address of an existing function to a function pointer and
modify it directly in the same function, the compiler will tack on a "CS:"
segment override, which will cause a page fault at execution time (Code
selectors cannot be used to write data.)  I don't quite see why they did 
this but the obvious work around of using another function to modify the 
actual code seems to work just fine:

  #include <stdio.h>
  #include <malloc.h>
  #include <stdarg.h>

  typedef int (* fntype)(char *, ... );
  
  char * fn;

  // Assembly language opcode to cause an immediate return:
  #define RET 0xc3

  void SetReturn(char * ptr) 
  {
          ptr[0] = RET;
  }

  main() 
  {
          printf("Hello\n");
          fn = (char *)malloc(128);
          SetReturn(fn);
          ((fntype)fn)("Hello\n");
          fn = (char *)&printf;
          SetReturn(fn);
          printf("Hello\n");
  }

This was compiled with the -5r and -s switches (only.)  Clearly there is 
a difference between the stack based and non-stack based libraries which
makes this sort of self-modifying code particularly hazardous to deal
with.

---------------------------------------------------------------------------


Q. How do I install a 32 bit interrupt vector?  How do I install a bimodal
interrupt?

A. Look up _dos_getvect, _dos_setvect, _dos_keep and _chain_intr in the
online help.  I don't know much about bimodal interrupts but the compiler 
comes with some sample code provided which demonstrates it.  I think the
idea is to write some assembly code which can be correctly executed under
either 16 or 32 bit segments and to make sure the interrupt vector is
hooked out without DOS4GW's interrupt code segment translation intervening.

---------------------------------------------------------------------------


Q. Are there any other WATCOM C/C++ caveats?

A. Here are some things I've learned while playing with WATCOM C/C++:

   1) Structure declarations that include shorts or bytes are highly
   unlikely to be in the physical order that they are declared.  This
   is because WATCOM re-orders the entries for efficiency.  This is
   within ANSI C specifications.

   2) ISR's do not properly load ES, and require a _loadds declaration
   to load DS.  Hence you should put the _loadds in and write a #pragma
   (that looks something like: "push ds pop es") if you are using any
   library functions.  Autoinitialization of arrays or structures is out 
   of the question, since WATCOM C/C++ uses rep movsd.

   3) To mix use of floating point in an ISR and in your main thread you
   must save the floating point state (fsave? fstore?) at the beginning 
   of your ISR and restore it at the end (frestore?).  This is because 
   the state of the FPU cannot be reliably known when the ISR is 
   executed (the stack may be full because from the main thread).  Because 
   saving and restoring the FPU state is so costly, I would recommend 
   against using the FPU entirely, within ISRs.

---------------------------------------------------------------------------


Got anything to add?  Suggestions?  Don't hesitate to send them my way.


Paul Hsieh
qed@chromatic.com
Graphics Programmer


  --- end of faq ---

  --- additions ---

From: MBLance@ix.netcom.com (Michael Lance)
Date: Sat, 18 May 1996 03:58:47 GMT

>By comparison, Microsoft is currently only supporting VC++ 4.x which can
>create targets for exactly one platform:  Win32.  That means Windows (Win
>32s is required for Win 3.x users.)  16 bit code is not an option.  For
>that you need to go back to VC++ 1.5, and I'm not sure how you can get
>your hands on that.  


MSVC++ 1.52 comes with MSVC++ 4.0.  Version 1.50 is pakaged with
version 2.0.

Michael Lance

 ----
From: pjunold@daimi.aau.dk (Peter Joachim Unold)

Perhaps you should mention that id-software doesn't use watcom/dos4gw 
anymore, but has swicthed to DJGPP.


>DJGPP beats all these compilers in two places: code generation and price.
>(It appears to produce the tightest code, and costs $0.)  However, it falls
>flat on its face in terms of platform support, compile speed and interface.

Well DJGPP is basically GCC, and I have yet to hear about any other
compiler supported on as many platforms as GCC. Check this info from
cygnus' www site:

Have a look at http://www.cygnus.com/misc/gnu-win32/. Although it's not too
stable yet, we'll soon have a great free win32 compiler.

>The support is there through the internet, but you have to be a real
>propeller head (even more so than with WATCOM C/C++) to get it working, let
>alone understand it.

Much has changed for the better since DJGPP v2.

Actually I think Symantec is doing OK these days. Their fast response to user
demands for java(tm) support properly gave them quite a few new customers.

   peter unold - pjunold@daimi.aau.dk

