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   +   +
     FFFFFF                AAAAAAAAA          QQQQQQ         QQQQQQ 
     FFFFFF               AAAAAAAAAAA        QQQQQQQ         QQQQQQ 

Written by Paul Hsieh
Revision 4.12
November 06, 2016

© Copyright 1996-2016, Paul Hsieh. All Rights Reserved.
This document may be freely distributed in any format desired so long as
the contents are not modified beyond non-obtrusive formatting.

Please note that although I've made a reasonable effort to verify the
material contained in this FAQ, I make no guarantees.  The things written
here are as true as I know them to be and should not be interpreted as
anything more.  None of WATCOM, PowerSoft/Sybase or TenBerry systems or
any other relevant company has officially endorsed this FAQ.  Furthermore,
I have no affiliation with WATCOM, PowerSoft/Sybase or TenBerry systems.

WATCOM, PowerSoft, Sybase, TenBerry Systems, QNX, IBM, OS/2, Microsoft,
Windows, Win32, Direct Draw, Direct X, Intel, Metaware, Symantec, Borland, 
CauseWay, Fastgraph, Varmint's Audio Tools, YackIcons, WordUp Graphics 
Toolkit, PC Magazine, NuMega, Bounds Checker, Soft ICE, Pharlap, PModeW 
etc., are copyrights/trademarks of their respective owners.



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.

This FAQ mixes advocation with technical information.  It has been written
this way because after years of posting on USENET this has become my
natural style of writing.


Frequently Asked Questions

These are very commonly asked questions that people ask about WATCOM C/C++.

. What is WATCOM C/C++?  What does it come with?  How do I purchase it?
. How do I obtain Open WATCOM C/C++?  How do I make it usable for Windows 
. Where are WATCOM C/C++'s related web/ftp sites?
. Why was WATCOM C/C++ so popular?
. How do I install STL for WATCOM C/C++?
. What features of Standard C++ does Watcom support?
. What's the syntax for ____?  How do I use the ____ tool?  How do I 
     make the code generator do ____?  I just don't get it.
. I think there is a bug in the compiler, what should I do?
. Why did so many games use the DOS4GW.EXE DOS extender?
. What libraries are available for WATCOM C/C++?
. How do I program for Direct X using WATCOM C/C++?
. Is the code WATCOM C/C++ produces the fastest/tightest?
. How do I use WATCOM's tools to help me optimize my code?
. How does WATCOM C/C++ compare with other C compilers?
. How do I debug DOS4GW apps under Windows?
. How do I make WATCOM apps to use with Soft-ICE, Bounds Checker or 
. How do I enable virtual memory for my DOS4GW application? How do I
     know exactly what interrupts dos4gw handles all by itself?  How do I
     know exactly what I have to do to use dos interrupts from protected
. I don't have the latest Windows SDK installed, can I point the WATCOM
     editor at another HLP file instead of WIN32.HLP?
. Why does my code work only when I compile with debugging info on?
. What is FLAT memory model?  What is the advantage of a 32 bit
     compiler such as WATCOM C/C++ over 16 bit compilers?  What are the
     differences?  Will I be able to move my 16 bit DOS code straight over 
     to 32 bit?
. I am getting this weird error message ...
. I am having malloc troubles.  It seems that I am trashing the heap 
     but I don't know how to debug it.
. How do I write directly to graphics memory?
. How do I install a mouse event handler?
. 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?
. What if I really need to compile a 16 bit model program?
. 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?  I am having difficulty porting
     code to WATCOM C/C++.
. Can I link external assembly files together with my C files?
. How do #pragma's work?  How do I use inline assembly language?
. How do I do compiled bitmaps?  How do I implement on-the-fly 
     generated code?
. How do I install a 32 bit interrupt vector?  How do I install a
     bimodal interrupt?
. How do I get rid of the DOS4GW banner?  How do I bind DOS4GW.EXE to
     my application?  How do I get rid of the external DOS4GW.EXE
     altogether?  What other DOS extenders can I use?
. How do I build and use DLLs for 32 bit DOS applications?  How do I
     run .EXE images straight from memory?
. How do I make WATCOM C/C++ work with the latest OS/2 Toolkit?
. Why is WATCOM C/C++ giving me errors when compiling
     stdio.h?  What is the correct order for the WATCOM paths in the PATH 
     environment variable?
. Are there any other WATCOM C/C++ caveats?
. Will WATCOM C/C++ support MMX?
. Why does WASM produce different results from MASM?
. How do I use WATCOM C/C++ and other compilers at the same time?
. How do I compile extremely long command lines?  How does the @file
     directive file work?
. How does one turn off a warning in WATCOM C/C++?
. I don't like the Watcom IDE editor VIW. Can I use another editor with 
     the Watcom IDE?
. My Watcom editor VIW has crashed and is now unusable. Reinstalling has 
     no effect. What can I do?
. I'm using the traditional chinese version of Windows with Watcom and
     the error messages generated by "wcc386", "wpp386", "wlink" and
     "wmake" are unreadable. What can I do?
. Does Watcom offer anything to let me check how much stack space is 
. Is there a macro like the __FILE__ and __LINE__ macros used by
     assert() to tell me which function I am in?
. If I click on a compiler error message in the IDE under Windows95 the 
     editor window comes up with the cursor on the right line. Under 
     Windows98/2000 only the taskbar button for the editor flashes and I 
     have to switch manually to the editor window. What am I doing wrong?
. So what is your story?  Why did you do this?

Cool contributions

These are contributions sent to me that do not correspond to a frequently
asked question such as above, but which nevertheless are worth including.

C01. Profiling and debugging all rolled into one using an external
     terminal connected by serial.  Contributed by Charlie Wallace.
C02. Convert WATCOM's help file format to a text file for easier
     reading and potentially for easier manipulation.


Questions with answers

. What is WATCOM C/C++?  What does it come with?  How do I purchase it?

A01. WATCOM C/C++ is an Open Source x86 based ANSI C++/C compiler with 
associated tools.  It supports various target operating systems.  You can get 
a more complete description of the compiler on the Open WATCOM web site, 
however here are the most notable things that are included:

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

At version 11.0x, the commercially supported version WATCOM C/C++ has come to 
the end of its life.  On June 30, 1999 registered users of WATCOM C/C++ were 
given an end of life notice.  It may no longer be purchased and support ended 
on June 30, 2000.

The compiler has been substantially resurrected in the form of Open Watcom.
Some proprietary libraries had to be removed when the compiler transitioned
from commercial to open source.  Some effort has gone into reconsitituting
these libraries, and Open Watcom generally has better functionality than the
last shipping commercial version.


. How do I obtain Open WATCOM C/C++?  How do I make it usable for Windows

.  Open Watcom C/C++ can be downloaded from the Open Watcom website.  In 
particular, it is currently available in binary and source form at:

Do not try to download a new version of WATCOM C/C++ on top of a previous 
version.  This will cause a mix of executables and files that will not 
function correctly.  Always, install WATCOM C/C++ into a fresh new directory, 
or only on top of the same version.

After downloading the Open Watcom binary, it will be ready for development of 
DOS (16 and 32 bit) and OS/2 programs.  To use it for Windows development you 
must download the Microsoft Platform SDK and convert COFF import libraries 
from VC++ 6.0 format to VC++ 5.0 format using Microsoft LINK.  Use the 
following command to perform this conversion:

    LIB newlibrary.lib /CONVERT /LINK50COMPAT /OUT:oldlibrary.lib

The source can be compiled with the binary version of WATCOM C/C++ installed,
or the previous commercial releases: WATCOM C/C++ 11.0, 11.0a and 11.0b.

There is an issue with compiling the IDE when Symantec's Norton AntiVirus is
running.  Norton AntiVirus should be disabled while building the IDE.


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

. These are the URLs that I am aware of:

WATCOM's home page
WATCOM C/C++ Technical documentation
Tenberry Software, Inc.
X2FTP mirror:
Official site for the WATCOM C/C++ FAQ
Miscellaneous WATCOM C/C++ and OS/2 device driver notes
Power View IDE

USENET Newsgroups

Open watcom newsserver:

Sybase "PFC Guide" newsreader:

On Compuserve, try PSLANG.

For tutorials on C/C++ (not specifically WATCOM):

C tutorials


. Why was WATCOM C/C++ so popular?

. WATCOM C/C++ is a very good tool. It was the first pure 32 bit C/C++
compiler widely 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 "" 
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 

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 criticized 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, added support for MFC and added
an assembler.  With 10.5 they added the award winning Blue Sky's Visual 
Programmer (which generates MFC code.) and have built in a higher degree of 
Visual C++ compatibility.


. How do I install STL for WATCOM C/C++?

. To use the STL with Watcom you should get Boris Fomitchev's STLport. 
When using STLport always keep in mind that version 11.0x of the Watcom 
compiler does not fully support the new ANSI/ISO standard and its possible 
not every class works as expected.  (OpenWatcom C/C++ comes with its own STL.)

To install STLport, you do the following:

1) Download a STLport distribution.  This can be found at:

2) Unzip the distribution to a directory of your choice. It might be a good 
   idea to let the distribution create a directory under your %watcom% 
   directory because then you can use the environment variable %watcom% which 
   Watcom sets during setup.

3) Turn off SGI IOStream support in file %stlport_include%\stl_user_config.h. 
   Where %stlport_include% is the STLport include directory. It differs 
   between versions. E.g. for Version 3.12.3 it was %stlport%\stl and for 4.0 
   it was %stlport%\stlport. Where %stlport% is the directory where you 
   installed STLport. Please read the STLport documentation for details which 
   you should do anyway.

4) Set the INCLUDE path to search in the %stlport_include% directory first.
   For example in the .BEFORE section of your makefile, you can add a line
   like the following:

        set INCLUDE=.;$(%stlport_include);$(%watcom)\h;$(%watcom)\h\nt

5) Compile the 'Hello, World!' application:

     #include <iostream>
     #include <string>

     int main() {
         std::string s = "Hello, World!\n";
         std::cout << s;
         return 0;

   If this compiles you can be sure that the installation was successful.

   The SLTport forums ( 
   include information on for to build cleanly with no warnings, support for
   SGI's IOStream, numerous bugfixes and other related discussions.


. What features of Standard C++ does Watcom support?

. As of version 11.0x the following list applies:

Supported features

  - bool Keyword
  - mutable Keyword
  - explicit Keyword
  - Namespaces
  - Run-Time Type Information (RTTI)
  - New Cast Syntax
  - Exception Specification

Not supported features

  - typename Keyword
  - Member Templates
  - New Template Specialization Syntax
  - Partial Specialization
  - Template Function Call Syntax
  - Method try Blocks


. What's the syntax for ____?  How do I use the ____ tool?  How do I
make the code generator do ____?  I just don't get it.

. 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, most of the tools will respond with proper
command line syntax.  (Just type "wcl386" at the command to see this.)

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

Remember, that the WATCOM C/C++ compiler was not designed with beginners in
mind.  If you are just starting to learn C/C++ then I is suggest you get
plenty of reading on C/C++ in general and OS-specific programming manuals
(I.e., DOS, Windows, OS/2, QNX, or whatever target platform you are
interested in building for).

For a deeper understanding of WATCOM C/C++ you'll need to learn at least
bits and pieces about what object files, libraries, dll's, makefiles, and
protected mode are.  Experienced programmers find that WATCOM C/C++ doesn't
have any real brick walls that other compilers have, but that coaxing it to
do what you want it to do often takes some patience and perseverance.  That
is the issue this FAQ is trying to address.

In general your pursuit of information when dealing with difficulties using
the WATCOM C/C++ compilers should be in the order of:  (1) Check the online
help files, (2) Check reference materials such as DOS or Windows programming
books, Watcom's online technical documentation (the web address is given
above) as well as this FAQ, (3) Post a question to the internet (including
the USENET newsgroups, or the WATCOM listserver listed above) (4) Contact
WATCOM directly.


. I think there is a bug in the compiler, what should I do?

. WATCOM C/C++ is a fairly compliant ANSI C/C++ compiler.  Most "bugs" 
that seem to be compiler related will turn out to be a misunderstanding on 
the part of the programmer.  You can bring up your problems on the openwatcom 
newsgroups, however, you should analyze the problem as thoroughly as possible 
before doing so.


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

. DOS4GW.EXE is the default 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 have lead
some programmers to desire the telltale DOS4GW banner.)


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

. I don't have a comprehensive list, but I know that Varmint's Audio
Tools, Fast Graph, WordUp Graphics Toolkit, ZSVGA, 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++.  They are apparently 
source compatible, however retain their own non-compatible object format.  
But from the #pragma API, this appears to be a good decision, as they end up 
being more general, in their calling convention descriptions.  Look at 
WATCOM's discussion on "#pragma's" and you can decide for yourself which 
calling convention you like.  Then when you do, you can set it up using 
WATCOM C/C++; a trick not similarly possible with Visual 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 available for WATCOM C/C++:

Graphics libraries

SciTech's MGL
WGT Watcom
Xlib Watcom
Watcom ModeX
PD Curses
TIFF Software
Zephyr's ZSVGA
D-Flat and
OWL NExt MFC-like library from Borland.
Turbo Vision+
Audio libraries

VAT Watcom 
SMIX Watcom 
DSIK Watcom

Other libraries

XBase  dBase interface lib.
zlib   compression library.

Some libraries like ACK, and YAKICONS, have simply not been maintained and 
cannot be used with the latest WATCOM C/C++ compilers.  The issue in these 
cases have to do with use of older 16 bit assembly code that have not been 
ported forward.  With the latest WATCOM C/C++ compilers, there are 
alternatives listed above, that should be used in their place.  Unfortunately 
this means that "Tricks of the Game Programming Gurus" has become obsolete.


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

  I am not a Windows programming expert but the following information
appeared on the USENET:

  >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.

But then Ed Mueller said:

  With 10.6, you no longer need to include windows.h supplied with the 
  Games SDK.  The macros you need to define are NOIME and NOMCX.

And Marty (an employee of WATCOM) said:

  In response to questions regarding the WATCOM C/C++ compiler and DirectX:

  Watcom C/C++ 10.6 and DirectX 2.0

  The newly released DirectX 2.0 CD has a WATCOM directory that contains a
  zip file that will make all of the necessary changes to the sample files
  to work with Watcom C/C++ version 10.6.  Once these changes are made,
  the makeallw.bat batch file can be run to make the sample programs.

  See the readme file in the WATCOM directory of the DirectX 2.0 CD for
  more information.

Here's the latest info from Rich Jones, (another WATCOM employee):

  Direct X 3:
  A patch is available from  The patch   
  file modifies your Direct X 3 installation, making the necessary changes   
  to it for Watcom compatibility.  This works only with Watcom C/C++ v11.0

  Direct X 2:
  The Direct X 2 SDK is included in Watcom C/C++ v11.0 (with the necessary   
  changes already made).

The Direct X 1.0 information he gave is no longer applicable.  It is likely 
that WATCOM no longer supports Direct X 1.0.  Rich also indicates that version 
10.5 or above is required to support Direct X programming. 

"Avocado Green" wrote the following on the old WATCOM List server:

  Here are some simple steps in using the Watcom IDE (10.6) to compile
  and run the DirectDraw example (DDEX3) included with the DXSDK.  I
  thought I'd save someone a few hours from messing with the make files.

  0.  Run the Watcom IDE (run it from the DOS box command line if it'd
      make you feel less guilty.)

  1.  Select menu option "File->New Project"
      Select the C:\DxSDK\Samples\DDex3 directory and enter
      "ddex3.wpj" as your project name
      Note:  If you installed the DirectX SDK in another directory
             other than C:\DxSDK, make the changes as appropriate.

  2.  Enter "DDex3" as the target name,
      "Win32" as Target Environment, and
      "Windowed Executable [.exe]" as the Image Type.

  3.  Select menu option "Targets->Target Options->Windows Linking Switches"
      Go to "2. Import, Export and Library Switches",
      In field "Library directories(;):[libp]" enter "..\..\lib"
      In field "Libraries(,):[libr]" enter "ddraw.lib"

  4.  Add these source files into your project:

  5.  Highlight the "ddex3.cpp" file and select menu option
      "Sources->Sources Options->C++ Compiler Switches"
      In field "Include directories:[-i]" add ";..\..\inc;..\misc;..\include"
      so it should read


      ...of course you've set your Watcom environment variables already,

  6.  Repeat step 5. for ddutil.cpp also, or you can perform step 5. on the
      folder (.CPP) (representing all .CPP files)

  7.  Select menu option "Target->Make" and watch the few warning messages
      go by

  8.  Select menu option "Target->Run" and enjoy your Watcom compiler
      running something other than "helloworld.c" (well, for me anyway)

The following file is required for patching the Direct X 3.0 SDK to work with

Other Direct X specific FAQ's may best be answered at Microsoft's web site. 


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

. The WATCOM C/C++ compiler was generally regarded as among the best in
terms of code generation.  For example, it produces 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 very competitive with WATCOM's.

My own internal testing indicates that VC++ 4.2 and WATCOM C/C++ 10.0a are 
within 10% of each other in performance (with VC++ having the slight edge).
However, in the August issue of Software Development magazine, a comparison
of WATCOM C/C++ 10.6 (which they describe as the "perennial performance
champion") versus MSVC++ 5.0 indicated that WATCOM still held a performance
edge.  Such tests are always subject to the particular bias of the chosen

However, among the reasons for choosing 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 and features are indispensible for the "pedal to 
the metal" coder.

Be sure to follow the recommended switches for compiling your code that are
given in the documentation.  Options such as "assume no aliasing" and using
"reciprocal and multiply" for floating point divides can cause the compiler
to make assumptions about your code that have great performance impact even
though the code generation techniques fall outside the rules of the ANSI
spec.  You should be sure you understand all the options for optimization.

The differences to note when comparing with Visual C++ is that WATCOM uses
register based parameter passing as well as using a superior inline assembly
paradigm.  These things may not translate to better C code generation, but
they end up being far better for integrating inline code, once you get to
the stage of doing hand optimizations.


. How do I use WATCOM's tools to help me optimize my code?

. WATCOM comes with 3 tools that make the code optimization process an
easy one:  Execution sampler/profiler, disassembler and debugger.

There is a commonly held belief that in most applications 10% of your code
will be executed 90% of the time.  That is to say, most applications tend to
be bottlenecked, with the tightest bottleneck causing the greatest
performance penalties.  With WATCOM C/C++ this still holds true, but not to
such a severe extent, since WATCOM tends not to produce any "bottle-necky"

It is for this reason that your first step in your optimization phase should
be to profile your code.  Even if your project is half complete, and not
representative of its final form, execution sampling and profiling can often
pinpoint unexpected bottlenecks in your code.

The execution sampler works by executing along with your code, randomly
gathering instruction addresses during its run.  The profiler then converts
the sample data into a chart which clearly shows what functions were called.
You can zoom into each function to see what lines of code are being
executed, and keep doing that right down into assembly level.  To do this of
course you have to compile your code with line number debugging information
(/d1 or /d2.)

Not too surprisingly, data collected on Pentiums may show a sample data on
machine instructions one after where the real execution occurred.  This is
because the Pentium tries to execute instructions in pairs and the delays
in one instruction may appear to be passed to the instruction it is paired

The other tool is the disassembler.  Using it you can see all the
instructions compiled and correlate them their source lines.  WATCOM C/C++
generally only uses 1 cycle instructions.  However, in order to strike a
reasonable balance between code size and performance, WATCOM also uses some
complex instructions.  The most notable being: mul, imul, div, idiv, movzx
and movsx.  Simply scanning for these instructions can help you see where
your data structures and type mismatching are causing sub-optimal code to
be produced.

Finally the debugger is a simple tool not only for catching your bugs but
for tracing through your code to see the path it is really taking.  Most
of the time the execution path for small projects is fairly clear to the
programmer.  But when multiple programmers are involved or your code
becomes very fragmented, it is not so clear.  Very often, simply tracing
through your programs can lead you into good insights about the performance
of your program.

These general principles can be applied to any compiler, however few
compilers can rival WATCOM in these tools.

For information about Pentium optimizations in general, Agner Fog has
written up an excellent reference work which can be found on the following


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

. 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 targeting multiple platforms is a practically realizable
goal.  Their 32 bit compilers have been around since about 1992, years
before Borland, or Microsoft had PC based 32 bit compiler technology
(apparently DJGPP/DJGCC had it, but was highly obscure by comparison, and
the fact that they've only just got their dos extender technology working
in 1996, puts a big question on just how long that product has been 
practically useful.)  However, their recent acquisition by PowerSoft has 
given them a highly acclaimed RAD tool (Optima++) that is based on top of 
the WATCOM C/C++ compiler; a joining of technologies that has caught their 
competitors with their pants down.

By comparison, Microsoft is currently only supporting VC++ which can
create targets for Windows.  Microsoft has gotten into a habit of tweaking 
their compilers and operating systems in lock step; creating more and more
conventions and odd things like "Thunking" (a Windows OS and VC++ specific
way of performing 16<->32 bit execution segment translations, which I 
have been lead to believe is disfunctional.)  Users of Microsoft compilers 
(and products in general) become locked into their level of technology be it
good or bad.  They also get locked into their "vision" as they are clearly
pointing developers to Windows 95 and Windows NT.  Of course OS/2, QNX and
other platforms will never be supported.  The code generator for version
4.x compares favorably with 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
familiar 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.
Their PowerPak solution does not completely map in the first megabyte of
memory which is problematic, and requires a lot of support to work around.
Last I heard, Borland had dropped PowerPak support completely.  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 RAD tool layered on top of
their non-standard Object Pascal.)

DJGPP beats all these compilers in one place: price.  For x86s up to the
486, the code generation is unbeatable, but currently does not optimize with
consideration for the Pentium (though a beta of that version of the compiler
is in the works.)  It also falls flat on its face in terms of compile speed,
interface and third party support.  DJGPP has only recently been robust
enough to produce targets that work under both DOS and Windows DOS boxes,
and the currently available Windows native 32 bit support is still in
development stages (and is a separate compiler.)  As of yet there have been
no Pentium optimizations incorporated into the code generator and don't 
count on MFC support.  User support is there through the internet. Standard 
game libraries such as WGT, Fastgraph and Direct Draw have not been ported, 
and are not likely to ever be.  (On the other hand, Pmode/W and SVGAKit from 
SciTech have been ported, very recently.)

I haven't heard so much as a peep from Metaware.  As for Symantec, I hear
they are focussing on java.  Its likely that in the face of VC++ these
companies felt they simply couldn't compete.  Indeed its hard to see how
any other compiler besides WATCOM C/C++ will survive Microsoft's latest
product juggernaut.


. How do I debug DOS4GW apps under Windows?

. You cannot use the IDE debugger for this.  WATCOM implements this with
remote debugging using two DOS boxes.  This scheme allows the target program 
to retain full control of its VM without interference from the debugger (for, 
example, you should be able to debug apps which take over the screen without 
any problems besides Window's ability to virtualize that mode.) So in theory, 
debugging should be more reliable.  For Windows 95/98 use the following 
procedure.  In one DOS box you run the windows server:

    winserv -trap=rsi

and in the other you run the debugger:

    %watcom%\binw\wd -trap=win <executable name and arguments>

The winserv program should be issued in the target executable's directory
while the wd program should be issued in the source directory.  Trying to
execute "wd -trap=rsi" will not work under Windows 9X.  Additional options
such as /NoGraphicsMouse and /Vga50 can be passed to to the wd command line.

This is essentially the same procedure used for remote debugging over a
serial cable (remote debugging.)  Be sure that the [386enh] section of
your system.ini contains the line "device=wdebug.386".  If you have
problems try explicitly entering the path for wdebug.386 (it should be
%WATCOM%\binw) and make sure that this file actually exists.  Be sure you
are running wd.exe from the %watcom%\binw directory, not the
%watcom%\binnt directory.

For Windows NT/2000/XP, the server should be run as:

    vdmserv -trap=rsi

and the debugger should be run as 

    %watcom%\binnt\wd -trap=vdm <executable name and arguments>

The "rsi" thing stands for "Rational Systems incorporated" which is the
former name of TenBerry Systems.  Similar solutions exist for other OS's.  For 
other DOS extenders, "rsi" is substituted by another suitable acronym, see the 
extender's documenation for more details  (Thanks to Eric Kenslow, "Gothmog" 
and Tomas Likens for the majority of this information.)

You must compile your application with debugging information to enable any
sort useful debugging.  This is done by giving a /d1 or /d2 to the compiler
and a "debug all" directive to the linker.  See the online help for more
information on each of these steps.

Unfortunately, even following the above steps to the letter, may not let you
reliably debug under Windows 95.  Commonly, developers can get the process
started, but some functionality, or simple prolonged use of the debugger 
eventually hangs the machine.  According to Terry Colligan (president of
TenBerry Systems):

  This is caused by a bug in Windows 95 involving the INT 1 handler
  (triggered for stepping).  Basically Win95 is not letting the
  debugger see the INT 1's.

  This bug in Win95 will affect *every* debugger which uses INT 1 --
  basically all of them.

He went on to indicate that it is possible to work around the problem which 
they (TenBerry Systems) have incorporated into their own products.

If you are developing an application that is purely ANSI (that is to say it
does not use low level graphics, sound, interrupt vectors, keyboard polling
or other DOS-specific capabilities) you can usually switch your application 
over to a Win32 console application.  The WATCOM debugger works directly in 
the IDE with Win32 applications.


. How do I make WATCOM apps to use with Soft-ICE, Bounds Checker or 

. Through information received from Richard Horrocks, Christian Schlange 
and an anonymous contributer who queried WATCOM about it directly, I have 
surmized the following procedure:

1) Compile with "-hc" compiler options to set the codeview debugger
   format, as well as your regular compiler options (including -d?
   debugging options of course!)

2) Link with "debug codeview opt cvpack".  By default "op symf" is set in
   the IDE, be sure to turn it off.

3) Generate a map file.  You can add "opt map" to the link options above
   (combining steps 2 and 3) or run DBG2MAP on the executable.

4) Run MSYM on the map file to get a symbol file that can be read.

Then use Soft-ICE/Bounds Checker/VTune as described in their manuals.  A 
common problem with NuMega's tools when debugging large applications is 
running out of memory for symbol information.  With Soft-ICE, you can 
expand the amount of pre-allocated symbol memory by setting the 'SYM=####' 
directive in the WINICE.DAT configuration file.  Alternatively you can 
reduce the number of symbols with the -d2 or -d1 instead of -d3, and by 
being selective about which modules you include debugging information for.

James Shaw writes:

  Here's a few details I've found regarding my comments on CVPACK.

  2335  From Microsoft's 'knowledge' base.

  "CVPACK's purpose is to remove duplicate symbol and type information and 
  rewrite the remaining information in a format optimized for CodeView 
  processing. The type indices for this remaining information must not 
  exceed 64K, because the index itself is a 16-bit value. Because this 
  index is part of the specification, it cannot be changed without breaking 
  the tools that depend on it, many of which are supplied by third-party 

  Therefore, if your packed symbols exceed 64K (ie. all real programs), 
  you're stuffed.

  I also think there's some problem using the technique you outline (and the 
  one Intel are peddling on intel.other_products.vtune) when you try and 
  link Tasm object modules. In this case cvpack balks saying "no 
  sstSrcModule present for detected module." Unfortunately, I have no 
  solution (except just putting debug info in those files which need 
  debugging). Obviously that's daft, as the bugs are never in those files 
  you suspect :-)


. How do I enable virtual memory for my DOS4GW application? How do I
know exactly what interrupts dos4gw handles all by itself?  How do I know
exactly what I have to do to use dos interrupts from protected mode?

. These and other DOS4GW specific questions are answered in the file
%WATCOM%\DOS4GW.DOC, and in the online help under the DOS/4GW section of
the user's guide.


. I don't have the latest Windows SDK installed, can I point the WATCOM
editor at another HLP file instead of WIN32.HLP?

. Tony Cook says:

  The name "win32.hlp" is hardcoded into the VIW executable.

  Suppose you wish to use an older SDK HLP file such as win31wh.hlp. [PH]
  You can do this by creating the file in %WATCOM%\eddat with the 

   #launch winhelp using the whole word, or special case, or _f or _n stripped
   # version as a partial key

   winhelp HELP_PARTIALKEY win31wh.hlp %1

  and then insert the line:

  menuitem "&Windows 3.1 Help" "Look up Win31 SDK help for '%1'" source %1

  (all one line) after the 'menuitem "&Windows Help"...' line in 

  Restart the editor and right click, you should now have a "Windows 3.1 
  Help" item on the content menu.


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

. Dom Laflamme asked this question on the USENET newsgroup
"" 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.  Except 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 debugging 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 debugging 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 settings 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 the "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.
  Your 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 "oa" switch
  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.

This is an all too common problem that can manifest itself in he most 
unexpected ways.  It is for this reason that having a familiarity with the
debugger and, in some cases, a good understanding of x86 assembly language,
is required.  Danie Conradie, emailed me with a case where in his external
assembly routines, he was using pusha/popa to save and restore registers
when calling a C function from his assembly in order to retain register 
coherency.  When compiling with full debugging the compiler is significantly 
less aggressive about register usage, and as a result there was no problem.  
However, with debugging turned off nothing worked.  The reason, of course, 
is that he was only saving and restoring the 16 bit versions of the 
registers where he should have used pushad/popad to save and restore the 32 
bit versions of the registers, and without full debugging info turned on, 
the compiler was dirtying all sorts of registers.

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

. WATCOM C/C++ can compile for either 16 bit or 32 bit.  The compilers
are named wpp/wcc/wcl and wpp386/wcc386/wcl386 respectively for 16 bit 
and 32 bit compilation.  Every DOS programming model under the sun is
implemented:  TINY, SMALL, COMPACT, MEDIUM, LARGE, HUGE (the 16 bit
models) as well as FLAT and LARGE32 (the 32 bit models).  Libraries are
not available for the LARGE32 bit model, and besides the FLAT model, the
others are obviously only supported by the 16 bit compiler.

So WATCOM C/C++'s sweet spot model is the 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 
situations, 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 

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 32 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 also
don't require selector loads for new data pointers or function calls are
restricted to 64K of data and/or code.

Familiar DOS/BIOS data areas such as 0A000:0000 and 0040: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:0x0400.  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.  (Or in the case of Windows; usually a
special address range with certain OS specific characteristics.)

(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 implementation 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.

For more information look under "Converting to WATCOM C/C++" in the 
Programmer's Guide.


. I am getting this weird error message ...

. 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:000?????  (basically segment 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.

If running the debugger is out of the question or somehow problematic for
you then you can generate a map file by putting "option map=myprog" on
your link command line, or putting "/fm=myprog" on your wcl command line.
This is most useful when you are compiling with debug info ("/d2" on your
compile command line.)   The resulting file will correlate the
line numbers in your program to relative addresses which can be matched
against the "Crash address" given above.

Often the target address will be in a library function.  This generally
means that either the parameters passed to the function are bogus, or
some global state that the function depends on has become damaged.
Global state is hard to be debug, but not impossible.  (Trying to do
this without a debugger is a hurting proposition.)  See ".  I am
having malloc troubles.  It seems that I am trashing the heap but I
don't know how to debug it." later on in the FAQ.

Another possibility that everyone seems to run into sooner or later is the
small stack limitation.  WATCOM C/C++'s stack, by default is 16K, so
declaring a local array in a function of more than 4096 ints, say, will
cause a stack fault with no clear explanation about the error.  This error
is ordinarily caught by debugging with runtime stack checking on (the
default, without the "/s" switch.)

But most of the time you are simply accessing memory you shouldn't be
(past end of an array, stuffing a pointer without first mallocing it,
inadvertently corrupting a pointer that you use later.)  Remember,
pointers are not in "far" format, but rather in "_FLAT" format.  So
0x0A0000000 is not the address of the VGA frame buffer, 0x0A0000 is.

(2) I type:

    wcl386 /l=dos4g hello.c

and get back:

    WATCOM Linker Version 10.6
    Copyright by WATCOM International Corp. 1985, 1996. All rights
    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.

(3) I'm using the IDE and am trying to compile an example program that comes
with "SupermundoGraph" and am getting messages like:

    wlink SYS dos op m op maxe=25 op q op symf @smg_ex1.lk1
    Warning(1028): smg_move_ is an undefined reference
    Warning(1028): smg_drawmap_ is an undefined reference
    file timmy.obj(C:\smg\src\smg_ex1.c): undefined symbol smg_resize_
    file timmy.obj(C:\smg\src\smg_ex1.c): undefined symbol smg_setclip_

"undefined reference" and "undefined symbol" indicate that something has
gone wrong in the linking process.  I am not very familiar with the IDE
but, chances are you have not added in the SupermundoGraph library
properly.  According to the v10.0 IDE help documentation, you simply add
the library (*.lib) as if it were a source file.  Alternatively, you can
add the library's path under the Targets->Target Options->Window Linking
Switches->Import export & Lib switches.

Also watch that you have selected the right directories for your project.
I usually set up my directories and build my project sources before
invoking the IDE (in the rare occasions that I have ever used the IDE.)
If you are not careful, you will end up building projects right in the
compiler's own Windows tool directories, which makes for file maintenance
headaches sooner or later.

Using the command line interface, you have to make sure your link file
(smg_ex1.lk1 in the above example) contains a "library [lib path & name]"
directive.  See the online documentation about the linker for more

If that's not it, then perhaps the example is not compatible with your
version of WATCOM C/C++.  In this case, you should contact the library
vendor and inform them of this problem.

(4) I'm just trying to compile a very simple application and I'm getting
something like:

    WATCOM C/C++32 Compile and Link Utility Version 10.0
    Copyright by WATCOM International Corp. 1988, 1994. All rights reserved.
    WATCOM is a trademark of WATCOM International Corp.
           wcc386 TEST.C
    WATCOM C32 Optimizing Compiler  Version 10.0a
    Copyright by WATCOM International Corp. 1984, 1994. All rights reserved.
    WATCOM is a trademark of WATCOM International Corp.
    C:\VC98\INCLUDE\stdio.h(23): Error! E1091: ERROR: Only Mac or Win32 
    targets supported!
    TEST.C: 32 lines, included 472, 0 warnings, 1 errors
    Error: Compiler returned a bad status compiling 'TEST.C'

You have installed or are using Visual C++.  (Installing other compilers may
cause similar problems.)  WATCOM can still be used when other compilers are
installed, however the environment variables INCLUDE, LIB, and WATCOM need
to be set to the default values set by WATCOM when it was first installed.

The WATCOM variable will be untouched by other compilers, so its usually 
best to redefine the INCLUDE and LIB environment variables in terms of 
%WATCOM% from batch files or makefiles.  For example in makefiles the
.BEFORE directive can be used for this purpose:

        @set INCLUDE=.;$(%watcom)\H
        @set LIB=.;$(%watcom)\LIB386

(5) I am getting linker errors from wpp386 that make no sense.  I have
everything externed and prototyped as far as I can tell.

One possibility is that you are trying to combine C and C++ code.  If it is
your intention to only write C, and not import C++ libraries, then you
should use the wcl386 or wcc386 compilers.  If you want to write C++ code,
you cannot simply mix C and C++ directly.  To import C code into a C++
project you must prototype them as extern "C" { } as follows:

extern "C" // c must be a capital C
        extern void Set_320_200();
        extern void Put_Pixel( BYTE Color, WORD x, WORD y );

The extern's publicize the symbol, and the "C" declares them as C symbols
so that they are linked without C++ attributions.  Thus they act as C
symbols, not C++ symbols.  This means their names are not mangled in the
objects, they cannot be overloaded, etc., etc.

Thanks to Mark Lassche for verifying this, and thanks to Eric Kenslow for
giving more a detailed explanation of extern "C".

(6) I am getting an unexplicable unmatched #if/#endif preprocessor error:

    f.c(99): Warning! W129: #endif matches #if in different source file 'f.h'

A missing linebreak after the #endif can generate this message. Make sure you 
have a linebreak after your #endifs.

(7) I get 


when I run WLINK in a DOS box on my Windows machine. What's wrong here?

Check which WLINK you're running. On Windows 9x/NT you should be running the 
WLINK located in %watcom%\binnt and on Windows 3.1x/DOS you should be running 
WLINK located in %watcom%\binw (check environment name PATH). If you've 
installed the Windows 3.1x/DOS tools accidentally on your NT machine please 
re-install Watcom C/C++.


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

. Someone on 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(99))[-1] 
  should be 99.  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 comparison
  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 desperate
  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
  mallocing it.

Paul Keys responded to the post above with a very good suggestion:

  Watcom has functions that can be used to debug the heap.  Functions such
  as _heapset, _heapchk, _heapwalk, are indispensible.  Using _heapset I
  have managed to find cases where I was using pointers to memory that had
  been mistakenly freed.  With _heapchk, I have tracked down where the
  heap lost its integrity.  And using _heapwalk, I was able to track down
  some rampant allocation that was slowly gobbling up all available

I have since used these functions; _heapchk () alone is worth while.  
Overwriting the bounds of a malloced piece of memory can also be tracked 
down, by simply sprinkling _heapchk () calls around the affected areas.


. How do I write directly to graphics memory?

. 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.  For an example of this see:

It is #pragma based, and assumes a little ASM and Mode X knowledge.  CGA
and EGA are no more challenging 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).  Many novices (including
myself, when I first tried it) make the mistake of thinking that they can
just pass in some appropriately cooked values into the required registers
as the VESA spec requires and just call int 10h.  Unfortunately this does
not work when the "es" register has to be stuffed with the segment for the
buffer that VESA fills in with mode info.  You need a protected mode to
real mode translation API to make dos allocations and simulate real mode
dos interrupts.  These are both achieved by using DPMI which is discussed
elsewhere in this FAQ (see .)

Revision 2.0 of the VESA SVGA interface has a 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:, and

The CauseWay DOS extender actually comes with an on-the-fly extender patch
for providing an extender wrapper for the VESA graphics pointers (much like
they have extended int 21.)

If you have a banked only SVGA and wish to virtualize it into a linear SVGA
Ivan Ristic has written up some sample code for doing precisely this:

Understanding of the above code requires a good low level understanding of 
Intel 386+ processors.

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


. How do I install a mouse event handler?

. This appears to be extender specific.  The CauseWay Extender has 
specific support for the int 0x33 (including sub-function 0xc) function.


. 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?

. DPMI stands for "DOS Protected Mode Interface" and was dreamed up by
Intel and Microsoft.  It is a method for extending DOS's functionality
for supporting 32 bit programming at the lowest possible level.  Windows 
95/98 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, CWSDPMI and DOS4GW itself are other

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:

(you need 'ARJ' to decompress this file; its available elsewhere on x2ftp)
An online 1.0 specification can be found at:

The major differences between 0.90 and 1.0 is that 1.0 servers must return
with exact error codes in the event of a failure.  Among its most common
uses are:  allocating 16 bit memory and 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 allocations.  The
programmers at "id" probably wrote their own memory manager which uses
conventional memory in addition to regular heap memory.

More information about DPMI can be found in the WATCOM C/C++ compiler users
guide under the section:  "INTERRUPT 31H DPMI FUNCTIONS".

The major short coming of DOS4GW is that its an incomplete implementation
of DPMI (0.90).  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.)  Fortunately 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 purchased 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
do this without mucking with %WATCOM%\BINB\WSTUB.EXE directly, by instead
modifying %WATCOM%\BINB\WSYSTEML.LNK; it should be self explanatory.) 

The 16 bit source code for WSTUB is also supplied, which makes the
kick starting procedure fairly clear (starting with version 10.0, 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.

Why would you ever want to paste 16 and 32 bit code together?  Well, the
main reason would be that you have a large database of 16 bit code that is
most logically accessed as if coming from an interrupt event.  I've also
heard rumors to the effect that using DMA is a 16 bit only operation, but
I'd have to investigate that more fully before confirming it.

For example, you might have a substitute mouse driver written in 16 bit code
that you don't want to run as a separate TSR because you want to retain the
old mouse ISR.  So you could install it at the start of WSTUB, spawn the 32
bit process, then deinstall it when you come back.

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.  David 
Vandewalle has used precisely this procedure to write a LAN monitor app.

Note that extenders that bind to the executable typically have their *own* 
wstub.exe in binary form (including their proprietary DPMI server), and 
hence don't allow for this sort of scenario to be set up. So this is really 
only applicable in this form to DOS4G/DOS4GW applications.  (Although it is
still possible to do this or something similar with any DPMI supporting 
extender, you will have to compile, load and manage all the 16 bit code 
separately yourself.) 


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

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


. 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?  I am having difficulty porting code to

. A list of these differences can be found in the online help.  Here's
a list of the major gotcha's:

- To get around the signedness default be sure to pass a "/j" on the
command line.

- WATCOM will, by default, use registers for its parameter passing
convention which makes it incompatible with regular COFF format libraries
and object files.  However, adding the extra declaration information via
"#pragma aux <function> frame;" will force WATCOM to pass parameters to
the function via the stack.  

- WATCOM's "wmake" utility parses a makefile format that is entirely
different from Microsoft's.  WATCOM decided to mimic UNIX as closely as
possible, while Microsoft went ahead and made their own standard.
Version 11.0 of wmake includes an /ms switch that supports Microsoft   
nmake files.   Also included is an nmake stub that converts nmake   
switches to their wmake counterparts and invokes "wmake /ms".

- If you do asynchronous variable updates (such as modifying global
variables in an ISR), you *need* to declare your variable as "volatile".
Other C compilers optimization strategies act as if all variables were
declared volatile, and can mislead you into thinking it is unnecessary to
declare your variables this way.

- 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 most discrepancies.


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

. 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 unnecessary complications.  Earlier versions (9.0) of the compiler
required the use of the "WOMP" utility to convert object formats.  Starting
with version 10.0, 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.

The most common problem when trying to link external assembly objects with
C/C++ objects is the name mangling/modification that the C/C++ compiler
does by default.  WATCOM C symbols in general are prepended with an
underscore ("_"), whereas assembler names are not modified in any way.
This can be changed with a #pragma directive (see , and the online
documentation for changing the symbol renaming convention used by WATCOM
C/C++.)  However, Eric Kenslow says that this is unnecesary.  WATCOM has
changed the meaning of "cdecl" recently, so how you deal with this may be
different depending on the version of WATCOM C/C++ you are using.

According to Mats Byggmastar, in C++ you should declare your external 
variables as:

        extern "C" int Variable;
        int Variable;

And your ASM external variables as:

        extrn _Variable:dword

In any event, if you are having problems linking asm and C objects together, 
use "wdisasm" ("wdis" in version 11.0) or any binary viewer for that matter, 
and see how the shared symbol names are being modified for each of your
objects.  As recourse, in C you can use the #pragma name modification
directive, and in assembly you can simply append your public/extern names
with underscores as necessary.  Modifying your assembly symbol names is
the method Eric Kenslow recommends.


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

. 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 either on
the stack or in certain x86 registers then you can assign which go where

2.  If you know that at link time you will need the exported function
names to be mangled in 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 <function>="<asm>" directive.

This system for dealing with inline assembly is very powerful as it allows
you to explicitly declare your register usage, so that your C and
assembly stitch together perfectly.  This 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(long *Source, long *Destination, int Length) 

in tight (i.e., small) assembly.  Using the WATCOM disassembler 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(long *Source, long *Destination, int Length);
  #pragma aux DWORDCopy = " rep movsd " parm [ESI] [EDI] [ECX]\
  modify [ESI EDI ECX];

The above function will 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 dwords) 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 taken care of by the FLAT model start up code.  To implement
this same thing with 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];)  You then
call "SetMode13()" as if it were a regular function, and WATCOM does the
inline pasting for you.

Why would you ever want to enter opcodes?  Well, Intel and AMD have been 
introducing new instruction set extensions faster than WATCOM has been 
releasing their compilers.  So at first, these new instructions require 
opcode encoding (starting with version 11.0 WATCOM is supporting MMX, Open 
Watcom C/C++ now correctly supports the cmovCC instructions.)  I had, in an 
earlier version of the WATFAQ.TXT claimed that rdtsc required opcode 
inlining, however this is not the case as Charlie Wallace informs me that:

  double RDTSC(void);
  #pragma aux RDTSC = " .586 "            \
  "       rdtsc                   "       \
  "       push    edx             "       \
  "       push    eax             "       \
  "       fild    qword [esp]     "       \
  "       pop     eax             "       \
  "       pop     edx             "       \
  modify [eax edx] value [8087];

is perfectly acceptable.  (Thanks to Tamas Kaproncai for suggesting the use
of floating point for the RDTSC value.)  However, recent attempts to encode 
"fsave", "fwait" and "frstor" using the inline assembler have lead me to some 
interesting results.  I found I had to use opcodes for these instructions 
(using v10.0a.)  The following code implements these instructions with some 
combined opcode and mneumonic trickery:

  static char FPUstate[0x94];

  void FPUSave(void);
  #pragma aux FPUSave =    0xdd " xor eax,offset FPUstate ";

  void FPUSaveToBuffer(char *);
  #pragma aux FPUSaveToBuffer = 0xdd 0x37 parm [edi];

  void FPURestore(void);
  #pragma aux FPURestore = 0xdd " and eax,offset FPUstate ";

  void FPURetoreFromBuffer(char *);
  #pragma aux FPURetoreFromBuffer = 0xdd 0x27 parm [edi];

  void FPUWait(void);
  #pragma aux FPUWait =    " wait ";

I'm currently stymied about how to encode something like "fsave [ebx+esi]".

Another reason for using inline assembly is to chose between short handed 
and non-short handed instructions (when differing opcodes produce the same 
assembly instruction.)  The Pentium actually has some performance penalties 
for executing some of the short-hand opcodes. 

Note that the division of strings into separate implicitely concatenated
strings is important.  That is to say " mov eax,ebx add ebx,ecx " will not
be parsed correctly, however " mov eax,ebx " " add ebx,ecx " will.  This
clearly falls outside of what one expects from C's parsing rules.  However,
I believe WATCOM is still inside the ANSI rules on this one since what is
parsed after a #pragma directive is implementation defined.  (I wouldn't
mind getting an official ruling on this one though.)

Starting with version 11.0 WATCOM C/C++ supports the "_asm" language 
extension, purely as a compatibility feature as most other PC based C 
compilers use it.  WATCOM still recommends the use of the #pragma aux method 
since it gives you and the compiler far more control.  Refer to the online 


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

. Its no big deal really.  Remember that CS, DS and ES are mapped to the
same physical space.  So in principle you need only 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 operands, 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 under the same scope, 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>

  // printf compatible function prototype
  typedef int (* fntype)(char *, ... );

  char * fn;

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

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

  void main(void) 
          printf("Hello\n");            // Call "printf" as normal
          fn = (char *)malloc(128);     // Get some memory
          SetReturn(fn);                // Assign function
          ((fntype)fn)("Hello\n");      // Call function with parameter
          fn = (char *)&printf;     // Point to "printf"
          SetReturn(fn);                // Reassign printf function
          printf("Hello\n");            // Call "printf" as normal

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

The details for doing compiled bitmaps are beyond the scope of this FAQ,
however the general idea is to construct a number of 

  mov [edi+offset],immediate

one after the other which plot the sprite.  This makes transparency
encoding an intrinsic part of the sprite.  However, difficulty with
clipping (especially in the x direction) and destination memory write
alignment makes compiled sprites a questionable compromise to a more
general run length copy routine.  For more information read the newsgroup:

Doing more exotic things like writing your own compiler and setting up
your own compiler environment with protected execution spaces are also
beyond the scope of this FAQ, but can probably be dealt with just using

Now, before you go off and get any not so bright ideas, read the following
USENET conversation:

  > Hi there, I was wondering how you need to set things up so you can modify
  > your code and make copies of your functions under DOS4GW/Watcom....  I've
  > tried copying the function's code around to several different areas, but
  > it always gets a GPF....  Here's a simple example that crashes, if anyone
  > has any idea how to make it work, please let me know!  Thanks in advance!
  > void printstuff()
  > {
  >  printf("HELLO\n");
  > }
  > void main()
  > {
  >  void (*pFn)();
  >  pFn = new char[500];
  >  memcpy( pFn, printstuff, 500 );
  >  pFn();
  > }

  The reason this doesn't work is because of the x86's relative addressing
  modes.  That is to say, that the >> printf("HELLO\n") << statement is
  translated to a *relative* call.  It gets translated to something like:

      mov eax,offset L1                     ; Pointer for string "HELLO\n"
      call relative ((offset printf)-($+5)) ; $ = current address.

  The x86 will automatically add in the current address to the relative
  offset and come back with the right address.  So in the copied version
  of the routine (in pFn()) you won't end up at the address of "printf"
  which you desire, because the relative difference was copied, rather
  than the physical address.

  There is no easy work around for this, and it is for reasons such as
  this that self-modifying code and related techniques, such as what
  you've tried to do are generally frowned upon.  The following two
  suggestions which fix the above program also serve to illustrate the
  flaw I am pointing out.

  (1) Instead of using 500, try using the number 31744 in both places.
  (Of course, the only reason this works is because printf is linked after
  your local functions.)

  (2) Rather than calling printf directly, assign the address of printf
  to a global volatile (just to make sure WATCOM doesn't try any
  simplification tricks to avoid using it) function pointer, and call
  the function pointer instead of printf directly.


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

. Look up _dos_getvect, _dos_setvect, _dos_keep and _chain_intr in the
online help.  Bimodal interrupts need an extra step or two to set up; DPMI
and x86 knowledge is a requirement. 

Here is an example for hooking out the timer interrupt in regular protected
mode.  Note the use of "volatile" on the Timer_Tick variable declaration.
This is an often over looked detail in this sort of asynchronous kind of

  #include <dos.h>
  #include <stdio.h>
  #include <conio.h>

  volatile int Timer_Tick = 0;    /* Must be "volatile" */

  void __interrupt New_Timer_ISR(void);
  void (__interrupt * Old_Timer_ISR)(void);

  void __interrupt New_Timer_ISR(void)
     Timer_Tick ++;
     Old_Timer_ISR();             /* Chain back to original interrupt */

  /*  Ordinarily using INT 01Ch is the preferred method, but INT 08h can
   *  also be used.

  #define TIMER_INTERRUPT (0x1C)

  void main(void)
     Old_Timer_ISR = _dos_getvect( TIMER_INTERRUPT );
     _dos_setvect( TIMER_INTERRUPT, New_Timer_ISR );

        printf( "%d\n", Timer_Tick );
     } while( !kbhit() );

     _dos_setvect( TIMER_INTERRUPT, Old_Timer_ISR );

In previous versions of the FAQ, I indicated bimodal interrupts are very
complicated and difficult to deal with.  Unfortunately, I was prejudiced by
my own example, where I was trying to do some really contorted things.  The 
truth is that if you are doing something simple, its really not all that 
hard.  My application was for trapping v86 mode application executed through 
system() when they made calls to software interrupts.  However, another 
practical application is pure performance improvements of interrupt calls, 
by avoiding the real mode to protected mode DOS extender pass up layer.

The general problem "bimodal interrupts" is trying to solve is the fact that 
an interrupt may occur either when the system is in v86 mode (essentially
real mode, with certain restrictions) or in pure 32 bit protected mode, and 
so under certain application contraints it may be desirable to have a 
separate v86 mode and protected mode service interrupt that would have 
essentially identical functionality.  To do this you need to use the DPMI API 
to install a "Real mode interrupt" (really a v86 mode interrupt; see the 
documentation recommended in ) and then use the regular DOS extender API 
(_dos_setvect(), _dos_getvect()) to install a protected mode interrupt.  
Ordinarily you need a shared data area (in the first meg of memory so that 
the v86 code can access it) to communicate the results of whatever you are 
doing so that the main thread of your application can react in an unified way 
regardless of which version of the interrupt was triggered.  What this does 
is it overrides the pass up that the DOS extender performs normally does, 
which can be very slow as it requires a switch up to protected mode and back; 
the switch is ordinarily trapped by Windows which will add other overhead.

You can find a somewhat simple example of a bimodal interrupt implementation

It was submitted by Fernando Anton of the "Spanish Lords" as a demonstration 
of a simple bimodal implementation for trapping the keyboard interrupt.  It
requires Borland's TASM assembler.

Bimodal interrupts can be extremely difficult to debug since you need a 
debugger that can trace in v86 mode as well as protected mode.  When I was
trying such things, I did not even bother with the WATCOM debugger, instead
going straight to NuMega's SOFT-ICE for Windows.  In some cases, I traced
through a little of the DOS extender, and Windows internals to see what was
going on.  But it is likely, that I was just exacerbating things with the
complication of what I was doing (my main 32 bit application was spawning
another 16 bit application after it rerouted a 16 bit interrupt to my 32
bit interrupt handler; so there were two applications, a dos extender and  
Windows that were all alive at any given time, and I only had sources to my

If understanding is your goal then keep the following in mind:

- DOS4GW initializes most interrupt vectors to point into the extender
itself.  These new vectors are just a translation layer through DPMI to
switch into real mode and call the old vector.

- Since function pointers (including those declared as __interrupt) are 32
bit offsets, the standard old DOS set/get vector int 21h functions will not
work in the standard old way.  Using the _dos_getvect() and _dos_setvect()
library functions is really the only reliable way to do ISR management.

- When a new 32 bit ISR is installed, no translation layer is installed
because it is not needed.  However, chaining is still possible.

- DOS4GW emulates the old real mode interrupts as closely as possible by
preserving the regular register values across the interrupt translation
layer.  However, the segment registers are clearly not preserved.  This is
not only because a direct Selector->Segment translation makes no sense but
because CS, and SS, must be set up to simulate a 16 bit context.

- DOS4GW implements its own version of int 21h, which looks very much
like a 32 bit extension of int 21h.  This is why it is referred to as a
"DOS Extender".  In these cases places where there might be Selector->
Segment translation issues, there has been a work around to use the _FLAT
model paradigm.  See the online documentation for more information.

- When you are *required* to pass a segment value to a 16 bit interrupt
routine, you need to use the DPMI 300h "Simulated interrupt" function.

Other DOS extenders such as CauseWay work in similar ways, on top of better 
DPMI services.


. How do I get rid of the DOS4GW banner?  How do I bind DOS4GW.EXE to
my application?  How do I get rid of the external DOS4GW.EXE altogether?
What other DOS extenders can I use?

. To get rid of the DOS4GW startup banner, bind your application to
"wstubq.exe" instead of the default "wstub.exe", or alternatively write
your own wstub.exe which does a "set DOS4GW=QUIET".

You cannot simply get rid of DOS4GW.EXE.  You need some sort of DOS
extender to drive your 32 bit app.  DOS4GW.EXE does not give you a link
option however other extenders such as DOS4G (the professional version of
DOS4GW) and CauseWay are plug in DOS4GW compatible DOS extenders that will 
let you link the extender right to your code.  This way, from the user 
perspective, your application is no different from old 16 bit .exe's out 
there.  This is very important for those interested in making tools that are 
easily transportable in a stand alone form.

The other main advantage of using DOS Extenders *other* than DOS4GW, is
that all of them seem to support the DPMI "800" call, which is essential
for mapping physical memory to linear memory so that you can access all of
graphics memory for some SVGA cards directly.

WATCOM's 3rd party support home page includes other DOS extenders that
work with their compiler.  Pointers to these can all be found either
directly from a www search engine or on the WATCOM www page.  Here's a
quick comparison of what is out there that I am aware of.  If you have
information to add or about other extenders (such as blinker, FlashTek)
please tell me so I can include it.

Pharlap/TNT - Large proven API, which supersets DPMI.  The extender is
external and a separate link process is required, but WATCOM supports it
as part of the basic compiler environment.  I don't know the current going
rate, but last I checked it had a $500 price tag.  PharLap is now owned by
venturcom.  Check it out here:

CauseWay - Fast, extended DPMI API, supports exe compression, links to final
exe, unlimited virtural memory (I accidentally allocated 800MB of memory
once, and since I had the hard drive space the app didn't complain!),
supports DLLs, plug in compatible with DOS4GW, $200.  This is a real no 
nonsense dos extender which truly supersets DOS4GW and which is at least as 
robust. The WATCOM debugger can be used with uncompressed CauseWay extended 
apps (be sure to follow the CauseWay installation instructions carefully), 
but CauseWay comes with its own debugger that can deal with compressed apps 
as well. It comes with an informative manual and plenty of sample code for 
assembly and WATCOM C/C++ usage (including examples of using VESA SVGA.)  For 
more information, check out

DOS/4G - What DOS4GW was based on.  It allows linking to your executable and
TSR programming.  Versions up to 1.97 appear to be limited to 64MB, though
apparently version 2.01 and above have fixed this problem.  They claim to be 
the extender used for Lotus 1-2-3, and thus guarantee system compatibility.     
There is varying pricing, but the main Watcom C/C++ upgrade option appears 
to cost $999.  See for more information.

WDOSX - Wuschel's DOS Extender - This extender is free.  I am not familliar
with it, so I cannot comment much about it.  For more information you can
go here:

DOS/32 Advanced - This extender is free.  I am not familliar with it, however
the author has made some claims about its superior performance.  For more 
information you can go here:

FlashTek - I know nothing about this extender (it is used by the WATCOM tools
themselves.)  For more information you can go here:


. How do I build and use DLLs for 32 bit DOS applications?  How do I run
.EXE images straight from memory?

. Ordinarily 32 bit DLLs support was not designed with 32 bit DOS in mind.
However, many DOS extenders provide this capability.  See  above for a
list of these DOS extenders.  There is no officially supported way to enable
DLL support using DOS4GW.EXE, however, there is a sort of "starter's kit"
available at the following URL:

Which comes with complete source, an example and a brief explanation about
how to enable DLLs under DOS4GW.

Running .EXE images straight from memory ordinarily requires DOS extender 
support.  Most DOS extenders have some sort of API for precisely this sort
of thing (though the free DOS4GW, does not.)  Clearly it is possible to 
spawn programs using system(), and you could store the .EXE in a RAM disk.  
So it remains to be investigated as to whether or not it is possible to 
simulate a RAM disk on the fly.


. How do I make WATCOM C/C++ work with the latest OS/2 Toolkit?

. I know nothing about WATCOM's OS/2 support, however Eric Lekven has
given me the following information:

  WATCOM does not ship its compiler with the newest OS/2 Toolkit and must
  be obtained on the IBM OS/2 Developer Connection CDROM or direct from
  IBM.  Unfortunately both require payment, although there have been
  promotional versions of the Developer Connection CDROM shipped with Dr
  Dobb's Journal magazine which contain the Toolkit for free.  Perhaps
  they will do this again when OS/2 Merlin ships.

  In order to use IBM's OS/2 Warp Toolkit header files you need to edit
  three of the files.

       Find the two identical lines containing
       #if defined(__IBMC__) || defined(__IBMCPP__)
       Edit these two lines to contain this
       #if defined(__IBMC__) || defined(__IBMCPP__) || defined(__WATCOMC__)

    mmio.h, mmioos2.h:
       Both of these have two lists of #defines, one for country codes,
       the other for keyboard codes.  The values are decimal.  However
       these files are non-ANSI in that these decimal numbers have leading
       zeroes.  Delete the leading zeroes from all these #define

Breckan Morris has verified this and recommends this over compiling with
the stack interface (/4s or /5s) which would also solve the problem.  He
also adds that there is also a line of the form:

  #if __IBMC__ || __IBMCPP__

which should be changed to

  #if __IBMC__ || __IBMCPP__ || __WATCOMC__

According to Vance Palodichuk, OS/2 4.0 (aka Merlin) has fixed the non-ANSI
leading zeros error from their mmio*.h files, and the modification listed by
Breckan above is sufficient.  I.e., you just have to add a "|| __WATCOMC__"
to one line of the os2def.h file to make it work.

It makes me wonder why IBM didn't simply add this modification themselves
just to make it that much easier to use the OS/2 toolkit.  This has to be
contrasted with Microsoft and Intel who have clearly gone out of their way
to support WATCOM C/C++.  It seems surprising to me that the relationship
between WATCOM and IBM isn't better since they have clearly been beneficial
to each other.


. Why is WATCOM C/C++ giving me errors when compiling
stdio.h?  What is the correct order for the WATCOM paths in the PATH 
environment variable?

. At the time of installation the environment in which the tools operate
is chosen.  I.e., there is a different setup in DOS, versus Windows, versus
OS/2 etc.  This boils down specifically to the PATH chosen.  In WATCOM C/C++
version 11.x, the following path order is used for Windows:


For MSDOS this order should be:


The reason for this is that WATCOM C/C++ actually comes with multiple 
compilers with different tool chain support.  Some of the executables are
Windows only binaries, while some are actually DOS applications.

Check your environment variables with the commandline "SET" command.


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

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

1) Structure declarations that include shorts or chars are highly unlikely
to be in physically packed offsets.  This is because WATCOM pads entries
to align them.  This is within ANSI C specifications which only
requires that offsets be in increasing order as they are declared.  Watcom
has a switch "/zp{1,2,4,8}" which allows you to change this behavior as
desired.  The default behavior differs between the 16 and 32 bit compilers.

2) ISR's do not properly load ES.  Hence you should insert a #pragma aux
macro (that looks something like: "push ds "" pop es") if you are using any
library functions in an ISR.  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) at the beginning of your ISR and 
restore it at the end (frstor).  This is because the state of the FPU cannot 
be reliably known when the ISR is executed (the stack may be full from FPU 
code in the main thread).  Because saving and restoring the FPU state is so 
costly, I would recommend against using the FPU entirely, within ISRs.  If
you must, it turns out that WATCOM C/C++ has some difficulty in encoding 
these instruction mneumonics directly; see  for details.

4) DOS4GW ISR's do not share the same stack with your main application.
This means that there are certain function calls that will not work:
longjmp and exit are the ones that immediately come to mind.  (Of course
any non-reentrant functions are off limits as well, but those are standard
ISR restrictions.)

5) DOS4GW has no provisions for TSR programming, however it is possible with
the professional version, DOS4G and possibly other extenders.  (I am not
aware of these capabilities in other DOS extenders.)

6) On pre-version 11.0 WATCOM compilers, the #pragma aux inline assembly 
language directive is limited to assembly sequences of up to 127 bytes or 
255 bytes depending on the version of the compiler.  Version 11.0 fixes this
problem.  (Rich Jones, an employee of WATCOM, says they can do 2GB <g>.)

For the earlier versions, WATCOM recommended using external assembly for 
longer assembly sequences.  But Charlie Wallace made the good observation 
that you can deal with this easily by breaking up your inline fragments into 

  void setup(void);
  #pragma aux setup =   \
  " mov edi,0xa0000 "   \
  " mov ecx,2000    "   \
  modify [edi ecx];

  void copy(void);
  #pragma aux copy =    \
  " loop1:          "   \
  " mov [edi],0     "   \
  " inc edi         "   \
  " dec ecx         "   \
  " jnz loop1       "   \
  modify [edi ecx];

  void main(void) 

The "modify" statements above are identical (the code generator is smart
enough to see that it doesn't need to restore then save the registers
between setup and copy), but as usual, they must describe the registers
modified in each inline #pragma.  If your flow logic is complicated in
such a way that you might jump from one #pragma to another, then you
should include all potentially modified registers for the collection of
#pragma's, in each #pragma's modify clause.

7) Although mentioned elsewhere, I might as well reiterate that WATCOM has
by default implemented "char" as "unsigned char".  This can be overridden
with the /j switch.

8) Apparently the WATCOM C/C++ tools have difficulty on DOS systems with
64MB of memory as well as with trying to spawn the WATCOM tools themselves 
inside of an application (via the system() command.)  This problem exhibits 
itself in different ways depending on whether or not you are using Windows, 
plain DOS or another DPMI server.  The work around, as suggested by Charlie 
Wallace and confirmed by Michael Devore, is to replace w32run.exe (in 
either %WATCOM%\binw or %WATCOM%\bin, depending on the which version you 
are using) with one of tntrun.exe, d4grun.exe or x32run.exe (i.e., use the 
DOS copy command; if things screw up you can always quickly incrementally 
reinstall from the CDROM.)  Apparently, the one which works is system 

9) ES is assumed to be equal to DS and the direction flag is assumed
clear.  For autoinitialization, structure copying and many library
functions, WATCOM C/C++ simply uses the "rep movsd" assembly instruction
which means that the direction flag must be clear and ES, must be set to
the _FLAT selector, as they are by default.

WATCOM does not allow you to add (E)SP, (E)BP, or segment registers to a
"modify clause" in a #pragma.  So if they are modified (by a BIOS call, or
by some inline assembly) you have to save and restore those registers
yourself.  Similarly the direction flag should be explicitly cleared with
the "cld" instruction if it is potentially set.

10) WATCOM C/C++'s stack, by default, is very small.  Depending on how you
write your code, this can be very limiting.  Basically, you should try to
avoid declaring arrays inside your functions, but rather declare them
statically, outside your functions.  If you need the array to be local
for recursive (or context) reasons you can either simulate your own stack
or simply enlarge the stack using the "stack" linker directive.

Here are the default stack sizes for version 11.0:

DOS           2K
Win 3.x       8K

DOS           4K
Win32 (95/NT) 64K
OS/2          72K (more than 64K is required for Warp 3.0+)

By default if, during runtime, your program overflows its stack it will exit
with a message saying so.  However, for performance reasons you are likely
to be tempted to remove stack checking (with the /s option.)  In this 
instance the stack will simply grow past its bounds until another error
occurs and likely exit with a page fault in code that crashes as a side 
effect of the corrupted data.  This makes even realizing what has gone wrong
somewhat difficult to arrive at directly.  As such it is a good idea to 
avoid removing the stack checking in your program during development until 
after it has been reasonably tested with its given stack.

11) WATCOM C/C++, by default, does not equate "enum"s to "int"s, but
rather to chars if the number of the enums is less than 256.  As described
in the WATCOM documentation, ANSI is ambiguous about this behavior.  I
believe this optimization is unique to WATCOM's compiler.  Clearly it can
cause problems for parameters and structure sizes for libraries,
especially if the libraries have been built for/by other compilers.  The
"-ei" compiler switch will force enums to be equated to "int"s.  (Thanks
Intel, for reminding me of this caveat!)

12) By default, the linker and library manager are case insensitive with 
respect to external symbol names.  This can pose problems for porting some 
UNIX based packages.  wlib takes the parameter "-c" and wlink takes the
directive "option caseexact" which make these tools respect case.

13) WATCOM C/C++ is more strongly typed with respect to function parameter 
passing than many other C compilers.  Other C compilers let you mismatch the
parameters passed on a given call from the prototype, because they pass all
parameters in a deterministic way onto a stack or register file, and 
therefore results tend to be predictable, if not well defined.  Instead of
using the stack, WATCOM C/C++ uses registers agressively, but not necessarily 
predictably.  Such coding practices are outside of the ANSI C specification
that can obviously lead to unpredictable results and thus should be avoided 
independent of using WATCOM C/C++.

14) The WATCOM C/C++ rand() function is exactly the linear congruence method 
recommended by the ANSI committee.  This function has been used by a number 
of other implementations.  The idea, I suppose was that this should provide 
a moderate degree of portability of random sequences from platform.  
However, for reasons beyond the depth of this FAQ, this function is far from
an ideal random number generator, and it is recommended that users requiring
good random number seek another solution.


. Will WATCOM C/C++ support MMX?

. Yes.  Starting with version 11.0, WATCOM C/C++ fully supports MMX 

Other extensions such as 3DNow! and SSE are not directly supported, however,
Microsoft, AMD and Intel have made some tools and mechanisms available to 
support these instructions in MASM, or through the use of include files that
can be used together with WATCOM C/C++.


. Why does WASM produce different results from MASM?

. There are several differences between WASM and MASM.  WASM is much 
smaller and does not cover nearly the scope of MASM's features.  Here are
some of the fundamental things that I have noticed:

1) WASM will not properly relocate _TEXT labels used as data addresses.  I
believe this is related to the comments in  about how WATCOM will 
sometimes throw up barriers that keeps you from writing self modifying code.
This is a bit of a problem for writing a 16 bit ISR hook that chains (since 
you would ordinarily prefer to avoid loading your data segment.)  Of course,
its not too hard to get the IP, so working around this is doable.


. How do I use WATCOM C/C++ and other compilers at the same time?

. The major concern when using other compilers are how the environment
variable INCLUDE is set to point in the WATCOM default include directory.  
Assuming that the variable WATCOM has been set, this usually means that 
INCLUDE = .;%watcom%\H.  The problem is that other compiler will use that
identical environment variable for its own include directory.

To do simple command line compiles, I recommend writing a batch file to
save %INCLUDE% then redefine INCLUDE to .;%watcom%\H then perform your 
compile, then reset %INCLUDE% to its original contents.

Within a handwritten makefile, you can simply put the INCLUDE definition in 
the .BEFORE section.


. How do I compile extremely long command lines?  How does the 
@file directive file work?

. In place of command line linker directives, one can use a file, say 
"proj.lnk" with linkers directives on seperate lines then pass this file to
the linker via an @proj.lnk parameter.

For example, your proj.lnk file may contain the following lines:

    option quiet system CauseWay
    option stack=32768
    name .\main.exe
    library ..\gfxlib\gfxlib.lib
    file mouse.obj, gui.obj, winman.obj, wrbmp.obj
    file trace.obj, rectman.obj

which is then passed the linker thusly: wlink @proj.lnk

Notice that options are not repeated and multiple comma seperated object 
files may appear per file directive.  

The WATCOM IDE builds makefiles on the fly which themselves will make 
*.lnk files on the fly using the %write and %append makefile commands.  
For a rough idea of how the link files for a particular kind of project, 
one can try to build a sample project from the IDE that follows the 
intended environment as closely as possible, build it, and observe the 
generated *.mk1 and *.lk1 files.

A typical "on-the-fly" generated link file set of makefile directives 
might look like the following:

    proj.exe : $(OBJS) makefile $(LIBS)
        @echo     Linking $(TGT)
        @echo opt quiet system CauseWay             > $^&.lnk
        @echo opt stack=32768                      >> $^&.lnk
        @echo name $^@                             >> $^&.lnk
        @for %%f in ($(LIBS)) do @echo library %%f >> $^&.lnk
        @for %%f in ($(OBJS)) do @echo file %%f    >> $^&.lnk
        @$(LINK) $(LFLAGS) @$^&.lnk
        @$(CW_DIR)\le23p $^@
        @$(CW_DIR)\cwc $^@

Echoing and redirection are alternative options to using the makefile
"write" and "append" commands, however it is slower.


. How does one turn off a warning in WATCOM C/C++?

. There are a few warnings that Watcom complains about that don't make
any sense like "must look ahead to determine whether construct is a 
declaration/type or an expression" or "no reference to formal parameter 
'...'" which should never have been given (parameters may be correctly 
ignored as a function pointer target, and WATCOM's look ahead mechanism 
actually does do the right and legal thing.)

While you can work around some of these warnings, some cannot be worked 
around which makes the "-we" compile option seem totally useless.  With
WATCOM C/C++ version 11.x, however warnings can be turned off will the
"#pragma warning" directive:

#pragma warning 640 10
    void setComplain (int (*complainFn)(const char * __format, ...) ) {
#pragma warning 640 9

Presumably the "10" and "9" are internal values corresponding to the warning


. I don't like the Watcom IDE editor VIW. Can I use another editor with 
the Watcom IDE?

. Yes, you can. In the IDE click the 'File' menu and then 'Set Text 
Editor'. A dialog pops up where you can enter the editor file name with 
parameter macros and select the editor type: executable or DLL. You find a 
detailed description in the Watcom IDE Help (Book 'Watcom Integrated 
Development Environment', sub-book 'Configuring the Integrated Development 
Environment', section 'Selecting Your Own Text Editor').


. My Watcom editor VIW has crashed and is now unusable. Reinstalling has 
no effect. What can I do?

. Find and delete any weditor.ini files you have. The editor will rebuild 
the defaults next time it's started. If you do any customization, save a 
backup copy of weditor.ini in case it gets corrupted again.


. I'm using the traditional chinese version of Windows with Watcom and the 
error messages generated by "wcc386", "wpp386", "wlink" and "wmake" are 
unreadable. What can I do?

. You can set the language of the messages with one of the following 

SET WLANG=japanese
SET WLANG=english
By default the tools check to see if codepage 932 is in operation (Japanese) 
and defaults to Japanese otherwise English. But for some reason Chinese 
customers sometimes see Japanese. WLANG is present in the following tools:


WBRG      WCC       WCC386    WPP       WPP386    WRC

but only seems to affect the first group.


. Does Watcom offer anything to let me check how much stack space is 

. Watcom offers the stackavail() function to check this. Please have a 
look into the online-documentation for details.


.  Is there a macro like the __FILE__ and __LINE__ macros used by assert() 
to tell me which function I am in?

. Version 11.0 has an undocumented __FUNCTION__ macro.


. If I click on a compiler error message in the IDE under Windows95 the 
editor window comes up with the cursor on the right line. Under 
Windows98/2000 only the taskbar button for the editor flashes and I have to 
switch manually to the editor window. What am I doing wrong?

. Microsoft has changed the window behaviour since Windows98/2000. Please 
read the following articles in Microsoft Knowledge Base:

 - INFO: SetActiveWindow() and SetForegroundWindow() Clarification:;EN-US;Q97925&LN=EN-US

 - INFO: Changing the Foreground Window in Windows 98 and Windows 2000:;EN-US;Q227043&ID=KB;


. So what is your story?  Why did you do this?

. I was a summer hire for WATCOM many eons ago, and I appreciate that
they gave me my first real job.  I have always been impressed by their
compilers and I've always wanted to see them crush both Borland and
Microsoft in the compiler arena.  (It looks like Borland will be laying
down for the count, but Microsoft is still there of course.)

WATCOM's most notable weakness is user support.  Their documentation is
very dry and generally does not fully explain all of the compiler's
capabilities.  I'm told this is the main reason a very high profile game
company stopped using their compiler in favor of another 32 bit DOS based
C compiler.  I've also found that lately, I'd been posting to USENET on a 
daily basis just answering people's basic questions about WATCOM C/C++.  
It is in the hopes of curing this problem that I've written up this FAQ.

Finally, I am hoping that people make contributions and possibly submit
corrections so that I can verify my own knowledge.  This process also
results in a more reliable FAQ.  Numerous contributions have been made
thus far (including some from WATCOM and Intel employees), and I have 
received a lot of positive feedback which has made it worth while.


Cool contributions

C01.  Profiling and debugging all rolled into one using an external
terminal connected by serial.  Contributed by Charlie Wallace.

[PH - The following contribution describes an alternative method for
profiling and debugging using a serial port connection to another
machine. I believe the idea is to redefine default the epilogue and
prologue code for your functions to communicate with a debugging or
profiling device.  The details were too complicated for me to verify.
However, for advanced WATCOM C/C++ users looking for an alternative
debugging or profiling method, the following may be useful.]

This is a small tip on using /ee /ep /en options of watcom, usually
these are used by the watcom profiler. I`ve found them useful for
debugging in the past, especially when you can`t load into the
debugger, like when watcom debugger had no support for X32,
what I`d do was compile with those options which adds a call
before and after every function call, so when the code locked
up I knew roughly where it was happening, I made the __PRO
routine emit the function name to the serial port at a
preset speed to a terminal, with a tab added at every level
entered, then the __EPI routine removed a tab and a new line
so on the serial terminal it looked thus :


where (i) and (o) are in and out, when the code locked up
only the last call entered would be displayed.

there are many other uses of this function, profiling with
other hardware, remember though this changes the execution
flow, you can compensate for it though, making a simple
debugger, debug options, watchdogs for memory leak and
code overwrites and so on . . .

However one caveat is to make sure you don`t add profile
hooks to the profiler code, write it in asm in a separate
asm file, (don`t use #pragma aux), and don`t call
a C function of your own that has been compiled with /ep /en,
otherwise it`ll recurse.

a small example of how it works, assuming a simple compile
with wcl386 /ep /ee /en test.c pro.asm

where test.c is something like , simple..

int foo(int a)
        return a-1;

        int a;

which is compiled to

        db      'foo'
        db      3
        push    ebp
        mov     ebp,esi
        call    __PRO

        ; does the function

        call    _EPI
        pop     ebp

        db      'main'
        db      4
        push    ebp
        mov     ebp,esi
        call    __PRO

        ; code goes here..

        call    _EPI
        pop     ebp

so get the function name, get the return address, esp will point to
it, subtract the length of the code before the __PRO call, ie the
push ebp + mov ebp,esi and add 1, use wdisasm to calculate this,
usually its 9, but I`m not saying it always will be, so check.
this byte is the length of the function name, subtract this from
the previous address just calculated and this gives you the
function name + length, ready to print out, or do whatever you

Here is a 32bit version of __PRO and __EPI, for 32bit flat mode.

pro.asm - snip here 8-X

; use this fragment to code your own routines.

        .model flat


        PUBLIC __PRO
        PUBLIC __EPI

; this routine gets called first
; usually like this, *- means subtract from current offset
;               db      'my_c_function'
;               db      *-function_name  (compute length of prev string)
;               push    ebp
;               mov     ebp,esp
;               call    __PRO

__PRO proc near
        push    esi
        push    eax

        mov     esi,[esp]

        sub     esi,9   ; this is the length of the
                        ; call __PRO+mov ebp,esp+push ebp+1
                        ; it may need to be changed to match different
                        ; compile options. check with wdisasm

        xor     eax,eax
        mov     byte ptr al,[esi]       ; length of function name
        sub     esi,eax
                                        ; esi -> function name
                                        ; eax -> length of string

; do what you will with these, EXCEPT ! call any function in C
; that you compiled with /ep or /en, otherwise it`ll recurse
; for ever (at least for a while anyway).

        pop     eax
        pop     esi

__PRO endp

; this gets called at the end of the function
; usually like this :-
;       call    __EPI
;       pop     ebp
;       ret

__EPI proc near

; do what you will here, just save all the reg's

__EPI endp


pro.asm - snip here 8-X


C02. Convert WATCOM's help file format to a text file for easier
     reading and potentially for easier manipulation.

Joergen Bech sent me a program which will convert WATCOM's .IHP files to
a text file, a table of contents file and an index file.  This will allow
you to peruse the file from your favorite text editor, or manipulate it
as you see fit.  The program is freely available at:

It assumes you have DOS4GW.EXE at your disposal, in your path.


Thanks for the feedback!

I have received numerous emails in response to my creation and public dissemination of the WATCOM C/C++ FAQ. They have, for the most part, been very encouraging. The contributions and corrections that have been sent to me have served to increase the quality of the FAQ tremendously. I must single out the efforts of Markus Neifer, and his Watcom QAF for his tremendous and significant contributions. Readers can rest assured knowing that the accuracy and content is being examined very carefully by discerning WATCOM C/C++ users. I would like to especially thank WATCOM Systems. I am honored to receive their attention and grateful to include the information they have provided. I would also like to thank Programmers Heaven for including a web link to the WATCOM C/C++ FAQ on their very prominent programming WWW page. ----------------------------------------------------------------------------- Request for information
I've tried to include everything I can, but this FAQ is clearly lacking in several areas. Open areas: - Information on Windows, OS/2 or QNX programming. - Writing ROMs or startup code. - Info on dealing with using TASM/WASM and the C/C++ compiler together. Got anything to add? Suggestions? Don't hesitate to send them my way. ----------------------------------------------------------------------------- Paul Hsieh

Valid HTML 4.0!