For two years, Microsoft C 5.1 has been the benchmark by which other C compilers are judged. Vendors of competing compilers always compare themselves against Microsoft's product. Some competitors have edged ahead of Microsoft C 5.1 -- Watcom C 7.0 produces faster programs; Borland's Turbo C and others are faster at producing programs. While Microsoft C 5.1 has remained at the top of the heap, it is no longer the leader in many categories.
The upgrade has finally arrived in the form of Microsoft C 6.0. Microsoft's answer to the competition includes a new programming environment, an improved code optimizer, a new version of the venerable CodeView debugger, and some new library enhancements. Pulling out all the stops, Microsoft has made clear its intent to keep its C compiler at the forefront of the industry.
Perhaps the biggest surprise for many is that Microsoft C 6.0 (MSC6) does not include any C++ extensions. With most other vendors jumping on the C++ bandwagon, it might seem odd that Microsoft has not followed the same path. Some industry watchers have opined that Microsoft has made a mistake by leaving out C++. I don't agree -- C++ is a language that is still maturing. Most C programmers are sticking with C; only a few have embraced C++ as their primary programming language. For now, C is the dominant programming language for professional developers of PC applications, and Microsoft is addressing this market.
You must use Microsoft's Setup program to install MSC6. The files on the distribution disks are compressed, and they can be expanded only by using the Setup program. Setup is a very good installation program; it gives you the choice of installing different sets of libraries and tools based on your needs. Additional libraries can be built later without having to reinstall the entire package.
MSC6 is disk-hungry; installing the MS-DOS version of the compiler, the programming environment, two memory models (small and large) each for the floating-point emulator and the coprocessor, and other tools used over 7 Mbytes of space on my hard drive. If you install all four memory models for all three floating-point options along with the OS/2 version of the compiler, you can easily use more than 12 Mbytes of disk space. Obviously, it is not possible to use MSC6 on a floppy disk-based computer!
One last change in the basic package may take some people by surprise: It is now distributed on 1.2-Mbyte 5 1/4-inch disks and 720K 3 1/2-inch disks. If you want MSC6 on 360K disks, you'll have to special order them after you've bought the package. Microsoft is offering MSC6 on CD-ROM, preinstalled and ready to run.
No, the question mark is not a typo. Looking at MSC6 you may wonder if Microsoft forgot to pack the documentation. Microsoft has minimized the paper documentation in their language products in recent years. Instead of providing thick books, Microsoft puts the majority of the documentation into on-line databases. MSC6 comes with only 940 pages of documentation, less than half the length of the manuals provided with Microsoft C 5.1 (MSC5.1). Going from the fat three-ring binders of MSC5.1 to the thin paperback manuals of MSC6 gives the impression that Microsoft has left something out.
The documentation isn't missing; it's just not where you'd expect it to be. The on-line help system is where the real documentation for MSC6 lies. There are nearly 2 Mbytes of help files covering every aspect of MSC6 in great detail. These help files are available either through the QuickHelp program, or from within the Programmer's Workbench environment.
In MSC5.1, the command-line compiler had a /HELP switch that displayed a simple list of compiler switches. The same switch in MSC6 is now available for virtually every program in the package. Instead of a simple command list, though, /HELP will invoke the interactive menu-driven QuickHelp system. This provides complete information on the program in question. Entering the command lib /HELP will bring up detailed information on the library manager utility. The scope of the information runs from an explanation of lib to complete coverage of lib switches and commands (with examples).
The lion's share of the help information is available only when you are working within the Programmer's Workbench. If you're working with OS/2, the QuickHelp utility can be used as a keyboard monitor, so that it can be popped up at any time for use. Unfortunately, MS-DOS users do not have the luxury of a TSR version of QuickHelp.
Considering the amount of on-line documentation, I was pleased to find that the seemingly small amount of paper documentation was actually very useful. There are two paperback manuals in the MSC6 box: the spiral-bound 380-page Microsoft C Reference and the 480-page Advanced Programming Techniques. The amazingly long title Installing and Using the Professional Development System belongs to an 80-page booklet that explains the installation process and the fundamentals of using the Programmer's Workbench environment.
The Microsoft C Reference begins with a section describing each program provided by Microsoft. For the compiler and utilities, a list of command-line parameters and switches is given. For nmake -- Microsoft's much-awaited enhanced make utility -- a reference to makefile statements is provided. The section on Code View presents a complete list of all debugger commands and data formats. The documentation for Programmer's WorkBench includes tables explaining the environment's numerous switches, macros, functions, and key assignments.
Following the utilities section, the Microsoft C Reference has a complete list of all library functions, providing information on prototypes, required header files, return values, and compatibility between operating systems. Each function has a one- or two-sentence description, which is adequate for an experienced C programmer. The appendices list printf and scanf format specifiers, key codes, and ASCII values. I think the Microsoft C Reference is the longest quick-reference manual I've seen, but it has quickly become indispensable.
A wide variety of topics are covered in Advanced Programming Techniques. It contains chapters on optimization, floating-point operations, memory management, the new in-line assembler, project development, debugging, graphics, and mixed-language programming. This how-to book provides details on how the MSC6 system can be used most effectively.
My overall impression of the documentation is that it was designed for an experienced professional. I would not recommend this product to someone just beginning to work with C. Beginners need hand-holding and detailed documentation, something that Microsoft is not providing with MSC6.
The Compiler and Tools
QuickC is not included with MSC6. However, the core compiler for QuickC is there; it can be invoked by the compiler control program with the /qc switch. Using /qc doubles the speed of compiles, but prevents you from using advanced optimizations. The compiler itself has actually changed in a number of areas from MSC5.1 to MSC6. The primary additions are in improved ANSI compatibility, a Tiny memory model, an in-line assembler, optimizations, "based" pointers (see sidebar), and a new long double type.
MSC5.1 stuck closely to the ANSI standard; MSC6 is just about on the money. New ANSI features in MSC6 include complete support for volatile, long values in switch statements, and support for "locales." A locale describes the numeric, money, date, and time formats for a given country. As with most MS-DOS C compilers, MSC6 only supports the C locale, which is identical to the locale for the United States, and is the only locale an ANSI-standard compiler must support.
Microsoft has finally recognized that some programmers want to produce programs in the simple .COM format. The new Tiny memory model is a modified version of the Small model; the primary difference is in how a program is linked. Link combines a special library with Tiny model programs to directly create a .COM file without a call to exe2bin.
The in-line assembler was introduced by Microsoft in QuickC 2.01, and it's now available in MSC6. The _asm keyword can preface a block of assembler instructions in a C program. The _emit function places a series of arbitrary byte values into program code. While the in-line assembler and _emit are non-portable, they do provide a convenience many programmers will find difficult to resist (see "DOS + 386 = 4 Gigabytes," DDJ, July 1990).
As predicted, Microsoft has increased the power of its optimizer. Many new optimization options have been added, including global optimizations that look at functions as a whole when analyzing a program. MSC6 is now in the same class as Watcom and Zortech when it comes to optimizations.
MSC5.1 was known for the infamous aliasing problem. An alias occurs in a C program when two different names refer to the same memory location. An optimizer can produce faster code if it can assume that no aliases exist. Under MSC5.1, the maximum optimization compiler switch (/Ox) told the optimizer to ignore the existence of aliases. Many programmers complained when MSC5.1 generated non-functional programs from code that contained aliases. Microsoft has changed /Ox in MSC6 so that it assumes aliases exist. You can still tell the optimizer to ignore the possibility of aliasing, but you must do so explicitly with the /Oa switch.
A new feature of MSC6 is that optimizations can be turned on and off within a source file through the use of pragmas. This allows you to explicitly protect a piece of code from strong optimizations, for example. MSC6 can enregister parameters, an optimization pioneered by Watcom C. Individual functions or complete source modules can be compiled with enregistered parameters. Normally the parameters to a function are pushed onto the stack before the function call is made. When enregistered parameters are in effect, parameters are stored in registers when the function call is made. This saves a considerable amount of pushing and popping of parameters on the stack, and can increase the speed of a program that makes numerous calls to functions with small numbers of arguments.
nmake is Microsoft's professional make utility. The older make program included with previous versions of Microsoft C was abysmally weak. Unlike its predecessor, nmake is compatible with Unix.
CodeView 3.0 has been awaited with great expectations. Earlier versions of Microsoft's pioneering debugger were very good but clumsy to use. Products such as Borland's Turbo Debugger were easier to use and more powerful. While CodeView 3.0 goes a long way towards answering its critics, it's still a few steps short of what programmers want.
Tiled windows are passe -- more information can be easily displayed in layered windows. Unfortunately, CodeView 3.0 uses tiled windows. With Programmer's WorkBench and other full-screen applications using a layered window system, CodeView seems a bit out-of-step. I could not use CodeView 3.0 with more than four windows open on a 25-line screen.
I also found CodeView 3.0 to be frustrating. I want CodeView to always come up in VGA 50-line mode with use of the 80386 debugging registers. While commands for CodeView can be placed in the TOOLS.INI initialization file, none of these commands change the default command-line parameters. There isn't even a CV environment variable to which default switch settings can be assigned. The compiler and linker both support environment variables that contain command-line switches; why CodeView doesn't is a mystery to me.
CodeView 3.0 can be run in extended memory (leaving more room for programs in main memory), but it can only do so when the HIMEM.SYS driver is loaded. HIMEM.SYS is incompatible with any other 386 control program, which prevented me from using Qualitas' 386MAX program, for example, to manage high memory when HIMEM.SYS is loaded.
CodeView 3.0 does not support the Virtual Control Program Interface (VCPI) for 386 programs, a standard developed by Phar Lap that allows multiple 386 virtual memory programs to operate in concert. Microsoft informed me that a VCPI version of CodeView may be developed, but did not name a release date. Make no mistake: CodeView 3.0 is superior to previous versions of the debugger. It has several new windows, including a "locals" view, which shows all variables local to the currently executing function. There is more flexibility in how windows can be tiled, and the command-line interface has largely been replaced by a set of keystrokes and mouse selections. Overall, CodeView 3.0 is a very powerful debugger. With a little work, it could be the best MS-DOS debugger available.
Benchmarks are infamous for being both controversial and subjective, yet they are one of the few empirical tools we have for comparing compilers.
Optimization has become one of primary ways in which vendors differentiate their products from the competition. An optimizing compiler performs an analysis on a program being compiled, generating a more efficient program. Optimizers can delete unused code and variables, improve register use, combine common subexpressions, precalculate loop invariants, and perform other tasks that improve program performance.
At best, optimizing a well-written program will improve its speed by as much as 25 percent. An optimizer will not replace inefficient algorithms with better ones. As the saying goes, "garbage in, garbage out." Most of the responsibility for a program's performance lies with the programmer. Improving algorithms and manually optimizing a program will often increase program speed by several orders of magnitude. The purpose of an optimizer is to make sure that the compiler is producing the fastest code possible from your source code.
In recent years, Watcom's C 7.0 has become the standard by which optimizing C compilers are judged. Watcom entered the market in 1988 with a compiler that produced very fast executable programs. To see how well Microsoft C 6.0 stands up to the competition, I have run the benchmarks for it, as well as the benchmark for Watcom C 7.0. I've also included benchmark results for Microsoft C 5.10. These results will show current users of Microsoft C how much improvement they can expect from the new version. Table 1 shows the results of these benchmark tests.
Four programs make up the benchmark suite. Dhrystone 2 is a standard industry benchmark designed to represent the "average" program. For this test, it was set to run 200,000 iterations.
DMath is a test of floating-point code generation of my own invention. DMath calculates the sines of the angles between 0 and 360 degrees using a simple series. A test of floating-point code generation, DMath contains only double data items, and it makes no library function calls.
XRef is a test of dynamic memory management and I/O speed. XRef is a filter program that creates a cross-reference of input from standard input. The cross-reference is displayed to standard output.
The last benchmark program is GrafTest, a program that exercises my low-level graphics library. GrafTest performs millions of function calls, and interfaces directly with video hardware.
All tests were run on a 20-MHz i386-based computer running MS-DOS 3.30. The computer was equipped with a 25ms hard drive, a 20-MHz 80387 coprocessor, and a 16-bit VGA video system.
Two compiles were done for the benchmark chart. One compile used the compiler and linker options I would use when generating a program with debug information in it. The other compile used full optimization, inline math coprocessor instructions, and 80286 code generation. Most compiles done during development are with full debugging information on. For MSC6, I ran two sets of benchmarks -- one with enregistered parameters, and the other without. Compile times are actually a combination of compile and link times. Timings are an average for five compiles/runs. The compiler command lines used are shown in Figure 1.
Watcom C 7.0 debug :-2 -7 -Os -d2 -ms Watcom C 7.0 opt. :-2 -7 -Oail -s -ms Microsoft C 5.1 debug :/c /G2 /FPi87 /qc/Zi /Od /AS Microsoft C 5.1 opt. :/c /G2 /FPi87 /Ox /AS Microsoft C 6.0 debug :/c /G2 /FPi87 /qc /Zi /Od /AS Microsoft C 6.0 opt. :/c /G2 /FPi87 /Oxaz /AS
Figure 1: The compiler command lines used in the benchmark tests. The /Gr switch was added to the Microsoft C 6.0 command lines when enregistered parameters were used.
Table 1 shows some clear trends. Enregistered parameters in MSC6 did not provide a significant increase in program speed in the DMath or XRef tests. The biggest gain from enregistered parameters is seen in the GrafTest benchmark, which makes hundreds of thousands of calls to functions that take two or three int parameters. Because Dhrystone 2 lacks function prototypes, MSC6 was unable to employ enregistered parameters. While Microsoft C 6.0 produced the fastest debug compiles and the best run times in three out of four tests, it fell far behind in run-time speed on the DMath test. Watcom maintains its position as the best compiler for mathematically demanding applications.
Watcom Microsoft Microsoft Microsoft Program & Test 7.0 C 5.1 C 6.0 C 6.0 no/Gr /Gr ----------------------------------------------------------------------- Dhrystone 2 time: debug compile 24.24 13.13 11.65 --- time: opt. compile 25.15 20.48 32.26 --- time: execution 31.88 29.42 27.25 --- .EXE file size 14,082 19,078 20,334 --- DMath time: debug compile 11.04 6.50 5.87 6.22 time: opt. compile 10.29 8.46 12.21 12.03 time: execution 30.39 40.64 40.48 39.41 .EXE file size 6,534 9,572 12,868 12,820 XRef time: debug compile 13.74 7.98 7.20 7.31 time: opt. compile 13.70 11.60 16.83 16.98 time: execution 33.48 32.42 32.41 32.37 .EXE file size 7,125 9,067 7,639 7,607 GrafTest time: debug compile 19.99 11.03 13.35 12.91 time: opt. compile 26.05 22.09 49.05 50.47 time: execution 27.71 28.78 27.09 26.85 .EXE file size 4,230 5,603 5,845 5,781
Table 1: Benchmark results for Microsoft C 5.1, 6.0, and Watcom C 7.0