Microsoft C to Borland C++ Conversion Guide BORLAND INTERNATIONAL, INC. 1800 GREEN HILLS ROAD P.O. BOX 660001, SCOTTS VALLEY, CA 95067-0001 Copyright 1992 by Borland International. All rights reserved. All Borland products are trademarks or registered trademarks of Borland International, Inc. Other brand and product names are trademarks or registered trademarks of their respective holders. If you're an experienced C or C++ programmer, but the Borland C++ programming environment and tools are new to you, then you should read this section before you do anything else. We appreciate that you want to be up and running fast with a new piece of software, and we know that you want to spend as little time as possible reading manuals. However, the time that you spend reading this section will probably save you a lot of time later. Please read on. Why Should You Use Borland C++, Anyway? You may have become accustomed to using Microsoft C over the years. If you were developing for the Windows environment in the past, Microsoft C and the SDK were the only game in town. And maybe you are a little skeptical that a newer product is superior to an old standby. Compared to the Microsoft development environment, Borland C++ is a real time saver from the moment you install it until you have debugged your program. For most typical applications, a program compiled with Borland C++ executes faster than when compiled with Microsoft C. The Borland C++ environment provides you with more and better supporting tools than Microsoft's, tools that are easier to use and that save you many hours of time during your software development cycle. The time that you save enables you to develop richer and better software faster, and helps your company to remain competitive no matter what its line of business may be. Let's cover these areas in greater depth. Installation. There is one and only one installation program for Borland C++, and it sets up all of the Borland C++ tools and resources in a single highly integrated directory structure. By contrast, you need to install several sets of software to be productive with Microsoft software development products. If some of your software is written in assembly language, you need to buy the Microsoft Assembler separately, and install it on your system. If you are writing software for Windows, first you must install Microsoft C6.0a, then pick and choose the tools, libraries, and header files from the Microsoft Windows SDK and decide where to install them. The installation of the Microsoft Windows SDK is a manual process with nothing to guide you or protect you from making a clerical error. Once you have installed Borland C++, you will realize its built-in productivity benefits. Rather than setting up INCLUDE and LIB environment variables, you tell the Borland C++ Integrated Development Environment (IDE) where your include files and libraries are, and the IDE does all the rest. PreCompiled Headers. By making good use of extended memory, using precompiled headers, and embodying other advanced compiler technology, Borland C++ compiles programs lightning fast even when all of the code optimization options and warning messages are enabled. In a typical comparison of compilation speeds MAKEing a widely distributed Windows application of moderate size, Borland C++ produced an .EXE file in 46 seconds while the Microsoft tools did it in 146 seconds, over three times as long. The program consisted of 12 C modules that contained 11000 source lines and 3 assembly language modules totaling 1000 lines plus all of the required header and include files. All possible compiler optimizations were enabled for this comparison. The test PC was a 33MHz 80486 with 16MB of memory and a SCSI hard disk with a 12 millisecond seek time. Integrated Environments. The Borland C++ IDE is quicker than PWB, which swaps to disk rather than using expanded or extended memory. It is much quicker and easier to edit several source files at once with the IDE. Turbo C++ for Windows is a complete Windows-based system that allows you to edit, compile, test and debug Windows applications while remaining entirely within the Microsoft Windows environment. The Turbo C++ for Windows program editor has a contemporary SpeedBar for point-and-click action on common editing functions. Borland C++ project files are interchangeable between Turbo C++ for Windows and the IDE, allowing you transparent use of the environment that suits your needs at a given moment. Debugging. The Turbo Debugger (TD) user interface is more intuitive to use than CodeView's, which retains many of the artifacts of its SYMDEB command- oriented predecessor. TD has commands to search memory for instructions or data elements, useful for debugging programs without source code or sometimes even with the source code. TD can be loaded resident to debug Terminate-and-Stay-Resident (TSR) programs. You can debug a program running in one PC remotely from another PC in cases where the run-time environment of a target program requires the maximum amount of available memory. Remote debugging with TD is possible via either a serial port or across a local area network (LAN). TD has companion driver modules which enable hardware-level debugging using the 386 debug registers. Turbo Debugger for Windows runs inside Windows and allows you to debug Windows programs using a system with only a single monitor. When invoked, it saves the Windows screen context, displays debugging info, then switches back to Windows. CodeView requires two monitors for debugging, typically a color monitor for Windows and a monochrome monitor to display debugging info. CodeView has none of the other features above, though in some cases an expensive add-on product provides them. Optimizations. Borland C++ gives you greater control over how the compiler optimizes your program with 13 independent classes of code optimizations. You can select the best combination of optimizations for your application, trading off execution speed and program size. Microsoft has just as many optimizations, but it is often not clear whether or not they overlap one another until you have experimented with the various choices. Borland C++ provides in-line code generation for 19 frequently used C functions, Microsoft C for an indeterminate number. An in-line function often generates more code than a function call does, but it executes much faster than library function calls, especially on 386 and 486 PCs with CPU cache memory. Ansi Standard. Borland C++ is fully compliant with the ANSI C specification and incorporates the latest C++ 3.0 draft specification. Compiling with Borland C++ gives you extensive warning diagnostics, many of which tell you things about your program that even a commercial LINT program will not. Using these diagnostics, you can spot a problem area and change your program before debugging it, often avoiding long debugging sessions. Development Tools. Borland C++ is a complete development environment that includes many productivity tools which are not part of Microsoft C. If you ever want to search a group of source files to find occurrences of the same or similar strings of text such as variable or function names, the Borland C++ UNIX-style GREP program will do the job. Resource Workshop For Windows development, the Resource Workshop is a single one-stop utility that integrates into a coherent hierarchy all of the Windows resources for a program, and allows you to conveniently edit, add, or delete any Windows resource from your program. It even allows you to edit the resources in an .EXE version of a program, a feature that is extremely useful for creating national language versions and for doing special customizations. Turbo Profiler The Turbo Profiler allows you to profile Windows and non-Windows programs alike, and to isolate time-consuming hot spots in the code. It measures the exact amount of time spent by your application on a function-by-function basis, or for each single statement executed by your program. Other tools The H2ASH utility generates assembly language structures from C or C++ header files, allowing you to easily keep C and assembly modules in sync. The TOUCH utility updates the file system date for a file or a set of files, so you can easily trigger an operation across a group of files such as a file backup or a program make. The OBJXREF program generates a cross-reference of global functions and variables used within object files and libraries, so you can see at a glance the relationship between function definitions and calls or among usages of global variables. Class Libraries. The Object Windows Library (OWL) is a C++ class library containing the classes used to program user interfaces for Windows applications. Turbo Vision is a similar library for DOS-based applications. Finally, the Borland C++ class libraries consist of reusable software to manage many objects used every day by programmers: sorted arrays, btree structures, linked lists, queues, hash tables, stacks, strings, and the PC hardware timer. Borland C++ includes the source code for most of these libraries, so that if you need to better understand how a function works, or if you want to derive a similar function, you can readily do so. These are the many reasons why you should use Borland C++. As you use it more, you will surely find some more reasons yourself. Here is a summary to give you a quick start in getting your Microsoft C program running with Borland C++. 1) Make sure your programs compile and run correctly with Microsoft C. There is no need to confuse things by converting programs that do not already work. If you do so, and something goes wrong, you won't know whether there was a bug in the original program, or the problem arose during the conversion process. 2) Start up the Borland C++ IDE (Integrated Development Environment) and open a new project, giving it the same name as your compiled program. 3) Select Borland C++ Keywords in the Options|Compiler|Source menu item of the IDE. This option tells the compiler to recognize the Borland C++ extension keywords, including near, far, huge, asm, cdecl, pascal, interrupt, _es, _export, _ds, _cs, _ss, and the register pseudovariables. 4) Now, add to the project the names of all of the C source (.C) files and .ASM modules for any assembly language functions you may have. If you are writing a program for the Windows environment, add .RC and .DEF files to the project as well. The Borland C++ IDE automatically keeps track of the other dependencies involving .H header files, .BMP bitmap files, .ICO icon files, .CUR cursor files, and assembly language include files. 5) Turn on all warnings with the Options|Compiler|Messages menu item or with the -w command line option. 6) Compile each module without any optimizations enabled. 7) Any compiler warnings generated by Borland C++ will alert you to potential pitfalls. These catch many subtle programming errors otherwise not found until you debug your program. Try to figure out why the warning was generated. You might try to add ANSI function prototypes and explicit typecasts whenever you are in doubt about the correctness of the executable program. 8) If you have any C-callable functions written in assembly language, refer to the brief discussion later on about C functions written in assembly language. 9) Test your program, referring to the information and the sample programs in the following sections. They explain and illustrate the differences between Microsoft C and Borland C++ in detail. 10) Finally, when your program is fully operational, recompile it with the required code optimizations enabled, and test again. 11) If you want to compile your program from the command line rather than with the Borland C++ IDE, generate a Borland make file with the PRJ2MAK utility. This set of steps is not exhaustive and it does not cover every possibility that might arise when converting Microsoft C programs, but it is a reasonably complete set of guidelines for you to follow. Compatibility Borland C++ supports the same set of keywords as Microsoft C 5.1 with the exception of fortran. Borland C++ also supports the same set of keywords as Microsoft C 6.0 with the exception of: -_based, _self, and _segname, because Borland C++ does not support based pointers - Borland C++'s keyword _seg is the equivalent of the Microsoft keyword _segment _emit; Borland C++ uses the pseudofunction _ _emit_ _, because this style allows addresses of variables to be given as arguments, and allows multiple bytes to be output; _emit, by contrast, works like an assembly DB, allowing one immediate byte to be output. If your program uses the Microsoft _emit, add the following statement to your program after the including dos.h: #define _emit(b) _ _emit_ _ (b) _fortran; use the _pascal calling convention instead Borland C++ provides _cs, _ds, _es, and _ss pointer types. See the section "Mixed model programming: Addressing modifiers" in the Borland C++ Programmers Guide for more information. If your program uses the fortran calling convention for functions, you can use the pascal calling convention instead. If you have many fortran functions in a source module, you might find it convenient to add the following statement just before all of the header declarations in your source code module: #define fortran _pascal However, pay attention to the differences between Microsoft C and Borland C++ in the scheme for passing floating point arguments, especially if your fortran function is written in assembly language. The __MSC macro If your Microsoft C program uses the DOSERROR structure, then, and only then, you need to add the definition of the _ _MSC macro to your program to preserve compatibility with the Microsoft variable names used within DOSERROR. In previous versions of Borland C++, you needed to incorporate the _ _MSC macro to use many Microsoft C DOS and BIOS functions. The statement #define _ _MSC needs to appear before the statement #include to use the Microsoft DOSERROR variable names. The Header Files You can use either the old Microsoft header file name or the equivalent Borland C++ header file name according to the following table: Original Alias alloc.h malloc.h dir.h direct.h mem.h memory.h A Memory Model Overview Although the same names are used for the six standard memory models, there are some fairly significant differences in memory allocation for the large data models in the standard memory configurations. In Microsoft C, all large data models (compact, large, and huge) have a default NEAR data segment to which DS is maintained. Data is allocated in this data segment if the data size falls below a certain threshold, or in a far data segment otherwise. You can set the threshold value with the /Gtn option, where n is a byte value. The default threshold is 32,767. If /Gt is given but n is not specified, the default is 256. In the other three memory models (tiny, small, and medium) under Microsoft C, both a near and a far heap are maintained. In Borland C++, the large and compact models but not the huge model have a default NEAR data segment to which DS is maintained. All static data is allocated to this segment by default, limiting the total static data in the program to 64K, but making all external data references near. In Microsoft's version of the huge memory model, a default data segment for the entire program is maintained which limits total near data to 64K. No limit is imposed on array sizes since all extern arrays are treated as huge (_huge). In Borland C++'s huge memory model, each module has its own data segment. The data segment is loaded on function entry. All data defined in a module is referenced as near data and all extern data references are far. The huge model is limited to 64K of near data in each module. A command line compiler option, -Fs, and integrated environment dialog, Options|Compiler, are available to allow the Borland C++ compiler to assume that DS is equal to SS in all memory models. You can use it when porting code originally written for Microsoft C that makes the stack part of the data segment. When you specify this option, the compiler will link in an alternate startup module (C0Fx.OBJ) that will place the stack in the data segment. Usually the compiler assumes that SS is equal to DS in the small, tiny and medium memory models (except for DLLs). The details of memory management functions, and the differences between Microsoft C and Borland C++ in this area, are covered in the discussion of MALLOC.H below and in the following section entitled "Converting Microsoft DOS Memory Management Functions". Constants and COMDEFs Defining data in the header files in your program can cause duplicate symbol errors at link time if the same header file is compiled into multiple modules. Microsoft C generates communal variable (COMDEF) records in the .OBJ files for global data allowing the linker to map duplicate global data to the same storage location. Borland C++ also supports COMDEF generation with the -Fc command-line option. -Fc tells the compiler to generates COMDEFs for global "C" variables that are not initialized and not declared as static or extern. So long as a given variable doesn't need to be initialized to a nonzero value, you don't need to include a definition for it in any of the source files. Some Conversion Hints Use Portable Functions Portable functions are those compatible with many different compilers and machines. Generally they are ANSI standard functions. Whenever possible, use only functions from the ANSI standard library (for /example, use time instead of gettime). The portability boxes in the Borland C++ Library Reference Manual will tell you if a function is ANSI standard. If you must use a function that's not in the ANSI standard library, use a Unix-compatible function, if possible (for example, use chmod instead of _chmod). Again, the portability boxes in the Borland C++ Library Reference Manual will tell you if a function is available on Unix machines. Use Function Prototypes Write function prototypes for all functions that do not yet have them. Function prototyping was added to the ANSI C standard to help you find subtle logic errors quickly. But you have to use function prototypes for them to help you. Avoid Machine Dependencies Avoid the use of bit fields and code that depends on word size, structure alignment or memory model. For example, Borland C++ defines ints to be 16 bits wide, but a 32-bit C++ compiler would define 32-bit wide ints. Use ANSI standard manifest constants to refer to the various values and arguments used by standard C functions. More generally, use manifest constants to define constant values rather than sprinkling your program with hard-coded "magic numbers". DOSERROR If you use the DOSERROR structure in a source module, insert the preprocessor statement #define _ _MSC before dos.h is included. /STACK Linker Option If you were using the link option /STACK:n in your Microsoft C application, initialize the global variable _stklen with the appropriate stack size. Source Program Conversion - Header by Header Borland C++ provides far-reaching source language compatibility for DOS and Windows programs written with Microsoft C Version 6.0a. The exceptions consist of nonstandard functions and manifest constants that are not often used. As a result, you should be able to compile almost any Microsoft C6.0a source program with few source code changes, if any, and have it working quickly with Borland C++. The number of exceptions where you need to make source code changes are listed below in alphabetical order arranged by Microsoft C header file name, along with suggestions and examples for how to treat them. If a Microsoft C header file is not listed here, this means that there are no known issues with its compatibility between Microsoft C6.0a and Borland C++. Eighteen of the 33 header files shipped with Microsoft C6.0a and the Microsoft Windows Software Development Kit (SDK) are fully compatible with Borland C++. The functional areas of C that require the greatest number of changes are memory management and graphics. If your Microsoft C6.0a programs make extensive use of functions in these areas, refer to the more lengthy sections that follow. They compare the Borland C++ and Microsoft C approaches, contain programs that guide you through a successful conversion, and compare functionally equivalent Microsoft C programs side by side. CTYPE.H The manifest constants defined in the header files and used in the various ctype functions are different between MSC6.0 and Borland C++. As long as you use the portable ctype macros, this should present no issue. If your program uses only the portable ctype macros, rather than referring to the ctype manifest constants, it will behave the same with either compiler. If your program does refer directly to the Microsoft C ctype manifest constants, add any of the following #defines as appropriate: #define _UPPER _IS_UPP /* upper case letter */ #define _LOWER _IS_LOW /* lower case letter */ #define _DIGIT _IS_DIG /* digit[0-9] */ #define _SPACE _IS_SP /* tab, carriage return, newline, */ /* vertical tab or form feed */ #define _PUNCT _IS_PUN /* punctuation character */ #define _CONTROL _IS_CTL /* control character */ #define _HEX _IS_HEX /* hexadecimal digit */ Borland C++ has no equivalent for the _BLANK manifest constant used within the Microsoft C version of the isprint macro. The following program shows how to define and use a portable isblank macro to test for a blank space. This is much better than using _BLANK. /* ISBLANK.C illustrates use of the portable character classification * function isblank. */ #include #include #define isblank(_c) isprint(_c) && !isgraph(_c) void main() { int ch; /* Display the blank character. */ for( ch = 0; ch < 256; ch++ ) { if (isblank(ch)) printf ( "The value 0x%.2x is a blank space.\n", ch ); } } When compiled and run with either compiler, ISBLANK.C displays one line of text, "The value 0x20 is a blank space." The Microsoft C6.0a ctype header also contains two undocumented macros useful primarily for the language syntax checking done by a C compiler: iscsym and iscsymf. DOS.H If your Microsoft C6.0a program uses the dosexterror function and its associated DOSERROR structure and variable names, add the following statement to your program to define the DOSERROR structure according to Microsoft C conventions: #define __MSC ERRNO.H The numeric values of the manifest constants for many of the error codes returned in the global variable errno differ between the Borland C++ errno.h and its Microsoft C6.0a counterpart. Many of these manifest constants are present to provide compatibility with UNIX. As long as your program refers to error codes using the manifest constants themselves, rather than any numeric values, it will behave the same with either compiler. The following pair of short code fragments illustrates this point, and underscores the role of standard C manifest constants in making programs portable: /* ERRNO.H Example 1 - This example IS NOT portable */ int ThisError; ThisError = errno; if (ThisError == 7) /* When reporting that an argument list that is too long, the Microsoft C run-time library assigns value of 7 to the error code, while Borland C++3.0 run-time library assigns a value of 20. */ printf("Arg list too long"); /* ERRNO.H Example 2 - This example IS portable */ int ThisError; ThisError = errno; if (ThisError == E2BIG) /* When reporting that an argument list that is too long, the manifest constant value E2BIG is returned by both Microsoft C6.0a and Borland C++3.0. */ printf("Arg list too long"); FCNTL.H The Borland C++ header file does not define the older UNIX manifest constant O_RAW. If your Microsoft C program uses it, add the following statement to your program after including fcntl.h: #define O_RAW O_BINARY FLOAT.H Between Borland C++ and Microsoft C6.0a, there are very minor differences in the values of some of the double precision (DBL_...) and floating point (FLT_...) manifest constants that specify the limits of computations. If your program explicitly references any of these constants, make extra sure to verify that it produces the expected results with Borland C++. Also, some 8087/80287 status word subconditions (SW_...) and floating point error signals (FPE_...) are defined as manifest constants in the Microsoft C header, but not in the Borland C++ header. If your program uses any of these manifest constants, add them to your program source code with #defines. GRAPH.H The Borland C++ Borland Graphical Interface (GRAPHICS.H) is quite different from the low-level graphics library supplied with Microsoft C, although the respective functions show a general one-to-one correspondence. If your programs currently use Microsoft's GRAPH.H, see the following section entitled "Converting Microsoft DOS Graphics Functions" for more details and examples. LOCALE.H The manifest constants LC_MIN and LC_MAX are not in the Borland C++ locale.h header file. If you use them in your Microsoft C6.0a program, add the following prior to compiling with Borland C++: #define LC_MIN LC_ALL define LC_MAX LC_TIME MALLOC.H The Borland C++ memory management functions differ somewhat from the memory management that is part of Microsoft C6.0a. If your programs currently use Microsoft's MALLOC.H, see the section entitled "Converting Microsoft DOS Memory Management Functions" for a comparison between the two memory management facilities and some practical examples of Microsoft C6.0a programs, before and after conversion to Borland C++. If your programs rigorously use only the ANSI standard C memory allocation functions, it is unlikely that you will have any difficulty recompiling and running your programs with Borland C++. If you use the DOS-specific memory management functions provided by Microsoft C, then you will have to take some care in converting your programs. MATH.H Older versions of Microsoft C used a 6-byte floating point format that predated the standard IEEE format. Microsoft C6.0a provides a set of functions to convert data between Microsoft's old format and the IEEE format. These functions are typically used for converting data files from one format to the other. Borland C++ does not support the proprietary Microsoft floating point format. Use the standard IEEE format instead, and convert all of your data files to IEEE format. Borland C++ does not provide the Bessel functions of the first and second kinds which are available in the Microsoft C6.0a run-time library: j0, j1, jn, y0, y1, yn, _j0l, _j1l, _jnl, _y0l, _y1l, and _ynl. PGCHART.H Borland C++ does not include functions to display presentation graphics, a library added to Microsoft C with Version 6.0a. PROCESS.H The Microsoft 6.0a functions wait is not in the Borland C++ header file. wait is a function available under UNIX. SIGNAL.H The Borland C++ header file does not define SIGUSR1, SIGUSR2, and SIGUSR3, manifest constants for user signals contained in Microsoft C6.0a. If your program uses them, you need to define them yourself prior to compiling with Borland C++. STDDEF.H The Borland C++ header file does not define the errno variable, as does Microsoft C6.0a. Instead the function prototype for errno is in Borland's errno.h, so add the following to your program: #include The function prototype for errno is also compiled conditionally by the dos.h and stdlib.h headers. STDIO.H If your program uses the high-level functions defined in this header file, your Microsoft C6.0a programs will compile and run with no changes. You need to be aware of a few things, however, if your program accesses any of the low-level elements defined in the Microsoft stdio.h header: The Microsoft manifest constant, _NFILE, defines the maximum number of files that your program can have open at one time. Replace all references to _NFILE with references to the Borland C++ equivalent, FOPEN_MAX. Better still, add the following statement to your program after #include'ing stdio.h: #define _NFILE FOPEN_MAX If your program does the low-level stream I/O table manipulations typically found in older K&R-style C programs, then all references to the Microsoft C6.0a array, _iob[], need to refer instead to the Borland C++ array, stream[]. The simplest solution is to add the following statement to your program: #define _iob stream The Microsoft C high-level macros getc and putc use the undocumented low-level _filbuf and _flsbuf functions, respectively. As long as your programs use only high-level portable stream I/O functions, this is not a problem. STDLIB.H If your program uses the function perror defined in the Microsoft C6.0a version of stdlib.h, add the following statement which adds the function prototype definition for the Borland C++ perror: #include Note that the ANSI standard defines the perror function in STDIO.H and not STDLIB.H. If your program uses the proprietary Microsoft function, onexit, replace all occurrences with the ANSI standard function, atexit. The easiest way to do this is with a single statement that makes the substitution with the C macro preprocessor: #define onexit atexit TIME.H The manifest constants CLOCKS_PER_SEC and CLK_TCK have different values for Microsoft C6.0a and Borland C++. If you use the defined macros then no source code change is required. If your program depends on the specific value, either redefine them with the Microsoft C values, or change your program to use the Borland C++ values. Assembly Language Functions Called by C Programs The conventions for passing arguments to functions on the stack are compatible between Borland C++ and Microsoft C6.0a for equivalent memory models (tiny, small, medium, large, compact, huge), and equivalent function types (near, far, cdecl, pascal, or _farcall). But there are some differences in the handling of return values by the compilers and these may require changes to your assembly language functions. These details are important for assembly language functions, but somewhat transparent for functions written in C. When your C function and your calling program are written, the Microsoft C and Borland C++ compilers adjust automatically for these differences in handling return values. Structures Returned By Value In a Microsoft C function declared with _cdecl, the function returns a pointer to a static location. This static location is created on a per-function basis. For a function declared with _pascal, the calling program allocates space on the stack for the return value. The calling program passes the address of the return value in a hidden argument to the function. Borland C++ returns 1-byte structures in AL, 2-byte structures in AX and 4-byte structures in AX and DX. For 3-byte structures and structures larger than 4-bytes, the compiler passes a hidden argument (a far pointer) to the function that tells the function where to return the structure. Integer Return Values. Microsoft C and Borland C++ are compatible in their conventions for returning simple integer variables. They return 1-byte variables (char) in AL, 2-byte variables (int, short, and near) in AX and 4-byte variables (long and far) in AX and DX. Floating-Point Return Values. In Microsoft C, _cdecl causes float and double values to be returned in the _ _fac (floating point accumulator) global variable. Long doubles are returned on the NDP stack. _fastcall causes floating point types to be returned on the NDP stack. _pascal causes the calling program to allocate space on the stack and pass an address to the function. The function stores the return value and returns the address. In Borland C++, floating point values are always returned on the NDP stack. Rules for EXTERNs and External Symbols Borland C++ applies different rules than Microsoft C6.0a for generating external symbols for the Turbo Linker, depending on whether the function type is cdecl (default) or pascal. For cdecl functions, the rule is C function_name --> _function_name, i.e. function name retains its case and the underbar character is prefixed to it. For pascal functions, the rule is C function_name --> FUNCTION_NAME, i.e. function name simply transformed to upper case. In general, you would use pascal functions only in Windows programs. The following set of changes to your assembly language source code should deal with many compatibility issues between Borland C++ and Microsoft C: (See the Turbo Assembler User's Guide and Programmer's Guide for more information.) 1. Add the following directives at the beginning of your program to tell the Turbo Assembler (TASM) how to deal with Microsoft assembler (MASM) compatibility: ifdef ??Version ; defined only by TASM MASM51 ; MASM 5.1 compatibility QUIRKS ; assemble with MASM quirks endif 2. If your functions written in assembly language use the MASM .MODEL directive for standard segmentation, then your functions will take the form: (The TASM MODEL directive is the equivalent of .MODEL.) public _asm_func _asm_func PROC FAR USES SI DI DS, ASMARG:WORD Change this to: public ASM_PROC ASM_PROC PROC FAR USES SI DI DS, ASMARG:WORD 3. Similarly, if your assembly language functions use older style segmentation, then your functions will take the form: public _asm_func2 _asm_func2 PROC _asm_func2 ENDP Change this to: public ASM_FUNC2 ASM_FUNC2 PROC ASM_FUNC2 ENDP 4. Far more preferable to the approach in item 3 above, modify your programs to use the TASM MODEL directive and the extended PROC syntax shown in item 2 above. The benefit of the extended PROC is that the all details of passing arguments and returning values are managed automatically by TASM, and you need not concern yourself with them. Converting Microsoft DOS Memory Management Functions C programs written for the conventional MS-DOS environment rely on the Intel segmented architecture to access data on the heap. The Intel segmented architecture limits to 64K bytes the amount of data that can be accessed with one setting of a segment register. It also forces an arbitrary division between the near heap and the far heap. The near heap is the heap space available in the default data segment after static and stack data have been allocated. The far heap consists of the remaining available conventional DOS memory after a program is loaded and its code, data, stack, and near heap space are allocated. Borland C++ and Microsoft C have slightly different but quite compatible heap manager implementations to deal with the intricacies of segmented architecture, but you need to convert Microsoft's non- standard heap function calls to ANS or Borland C++ function calls. Borland C++ memory management design and implementation are more robust than Microsoft's. These are the advantages of Borland C++ memory management: When a Borland C++ program starts up, the Borland C++ memory management functions treat all of the available conventional DOS memory as a single free far heap block. When a Microsoft C6.0a program starts up, its heap management run-time library normally allocates _amblksiz bytes of memory as the initial free far heap space. The Microsoft global variable _amblksiz has a default value of 8192 bytes. Subsequently, the Microsoft C6.0a heap manager adds _amblksiz bytes of memory to the far heap whenever it has allocated all of the free far heap space and needs to get more from DOS. If your program uses the heap in an extremely dynamic manner, you will find Borland C++ memory management faster. Borland C++ does not allocate memory blocks on the heap when a program requests a block size of zero bytes. This is treated as an error condition, because a heap allocation of zero bytes is logically inconsistent with good programming practice. Microsoft C allocates a heap block of zero bytes without indicating an error. Borland C++ satisfies any single request for more than 64K bytes of heap space if your program is compiled with an appropriate memory model, compact, large, or huge. All of the far heap management functions support huge heap blocks, those that are greater than 64K bytes in size. Only the Microsoft C6.0a halloc and hfree functions allocate huge heap blocks. When a program releases a memory block from the heap, the Borland C++ heap manager cleans up free heap space. It also links together any free heap blocks that are consecutive in memory to form a single larger free heap block. This allows Borland C++ to reuse free heap space when your program makes a subsequent heap allocation request. With Microsoft C heap management, the free heap space remains fragmented, and it sometimes does not get reused. If your program, compiled under Microsoft C6.0a, allocates and deallocates memory very frequently, there is a reasonable probability that it will be unable to obtain a memory block to satisfy a memory allocation request. Borland C++ allows your program to determine the status of free memory on a heap. However, it does not allow you to examine the contents of free heap memory, which is really not owned by your program. Microsoft C permits you to examine the contents of free heap directly. But neither memory management scheme can prevent your program from overwriting free heap memory if a pointer goes astray. The Microsoft C functions that expand the heap do not move heap blocks in memory. The Borland C++ realloc functions sometimes relocate heap blocks in memory to increase the probability that a request to grow a heap block will be successful. As a rule, you should always make sure that any pointers aliased to heap blocks are updated after a realloc function. Microsoft C Based Heaps The nonstandard based heap feature was introduced initially by Microsoft with Version 6.0 of Microsoft C. Borland C++ does not support based pointers, and it has no function prototypes (function names _b...) for using the based heap. You would typically use based pointers in a large or huge memory model Microsoft C program to give you a faster method to accessing data than using the far heap. If your Microsoft C program uses based heap functions, you can take one of two possible courses of action: 1. Recompile your program with Microsoft C6.0a adding the following statement at the beginning of your program: #define _MSC_VER 510 This directive forces the Microsoft C compiler to generate warning or fatal error messages for all references to based heap functions and the related elements _based, _segment, _self, and _segname. Replace the based heap functions with comparable far heap functions, change all references to _based pointers, remove all definitions of based variable types, and check out your program for correct operation. Finally, recompile your program with Borland C++. 2. Compile your program with Borland C++, and replace all based heap functions with borland far heap functions (farheap...), delete all _segment variables, and change the references to _based pointers. Now, check out your program for correct operation. Two sample programs, BASE_BEF.C and BASE_AFT.C, show you how to deal with the Microsoft C6.0a based variable functions and constructs. BASE_BEF.C exercises the Microsoft based variable and based heap memory management functions. BASE_AFT.C achieves the same end result by using the Borland C++ farheap instead of the Microsoft based heap. These programs are available for download (see the appendix for more details). General Comparison of Heap Functions The following sections contain a comparison of Microsoft C and Borland C++ heap functions. Two sample programs MFARHEAP.C and BFARHEAP.C show you how to convert from Microsoft C6.0a far heap calls to Borland C++ far heap calls. MFARHEAP.C exercises the Microsoft far heap memory management functions prefixed by the _f symbols. BFARHEAP.C achieves the same end result by using the Borland C++ farheap functions. These programs are available for download (see the appendix for more details). heapadd functions. The Microsoft heapadd functions, _heapadd and _bheapadd, expand the size of the appropriate heap by requesting additional memory from DOS and adding it to the threaded list used to manage heap space. Note that all of these functions are non-portable and non-standard. When a Microsoft C6.0a program starts up, the heap management run-time library normally allocates _amblksiz bytes of memory, but less than the total amount of unused DOS conventional memory. The default value for _amblksiz is 8192. Subsequently, the Microsoft C6.0a heap manager adds _amblksiz bytes of memory to the far heap whenever it has run out of free heap space. Borland C++ has no corresponding heapadd functions because it manages free heap space differently. When a program compiled with Borland C++ starts up, the heap management run-time library allocates all of the unused DOS conventional memory as free far heap. Recommended Action: Remove heapadd function calls, or insert the following #define which causes the C preprocessor to ignore all occurrences of the function call: #define _heapadd(a,b) expand functions. The Microsoft C6.0a expand functions, _expand, _bexpand, _fexpand, and _nexpand, change the size of a previously allocated block of heap memory. The size of a memory block may become either larger or smaller as the result of a Microsoft C6.0a expand function. An expand function does not move a block around in memory to make it larger. If an expand function cannot increase the size of a heap block because the memory above it is already allocated, it returns an error. Borland C++ has no corresponding expand functions because it manages free heap space dynamically, but the Borland C++ realloc functions, realloc and farrealloc, perform a task similar to the expand functions. These functions do relocate a heap block if required, so they are less likely to fail to expand a heap block than the Microsoft C expand functions. Recommended Actions: Substitute realloc function calls for Microsoft expand function calls, using realloc in place of either _expand or _nexpand, and farrealloc in place of either _fexpand or _bexpand. Since realloc returns a pointer to the memory block, which may have been relocated, you will also have to make sure that you always use the new pointer value when referring to data in the reallocated heap block. If possible, use the ANSI standard realloc function in preference to the DOS-specific farrealloc. heapchk functions. The Microsoft C6.0a heapchk functions, _heapchk, _bheapchk, _fheapchk, _nheapchk, check the consistency of an entire heap. With Microsoft C6.0a memory management, there are three possible error conditions: the heap header control area is invalid, the heap area is uninitialized, or a heap node contains invalid data. Borland C++ provides the heapcheck and farheapcheck functions that accomplish the same objective as the Microsoft heapchk functions. They return only two error conditions: the heap area is uninitialized, and the heap is corrupted. Recommended Action: Substitute heapcheck function calls for Microsoft _heapchk function calls, using heapcheck in place of either _heapchk or _nheapchk, and farheapcheck in place of either _fheapchk or _bheapchk. The sample programs MFARHEAP.C and BFARHEAP.C in the following section entitled "Converting from Microsoft Heap Management to Borland C++ Heap Management" show how this is done with a #define for _fheapchk. heapmin functions. The Microsoft C6.0a heapmin functions, _heapmin, _bheapmin, _fheapmin, and _nheapmin, release unused heap memory to DOS. Borland C++ has no corresponding heapmin functions because it manages free heap space differently. See the discussion under heapadd Functions. Recommended Action: Remove heapmin function calls or insert the following #define which causes the C preprocessor to ignore all occurrences of the function call: #define _heapmin() heapset functions. The Microsoft C6.0a heapset functions, _heapset, _bheapset, _fheapset, and _nheapset, check a heap for consistency and initialize all bytes of free heap memory to a constant value. Your program can later verify that the heap has not be overwritten by a stray pointer by checking all free heap memory for the same constant value using a matching heapchk function. Borland C++ provides the heapfillfree and farheapfillfree functions that accomplish the same objective as the Microsoft heapset functions. Both the Microsoft heapset and Borland C++ heapfillfree functions return the same error conditions as their corresponding heapchk functions. Recommended Action: Substitute Borland C++ heapset function calls for Microsoft _heapset function calls, using heapset in place of either _heapset or _nheapset, and farheapset in place of either _fheapset or _bheapset. The sample programs MFARHEAP.C and BFARHEAP.C show how this is done with a #define for _fheapset. heapwalk functions. The Microsoft C6.0a heapwalk functions, _heapwalk, _bheapwalk, _fheapwalk, and _nheapwalk, traverse the heap and return a heap structure containing information about the next heap entry. Prior to calling a heapwalk function, you initialize the heap structure with a pointer value, either to a valid heap block, or NULL, if you want to get information about the first block in the threaded heap list. The Microsoft heapwalk functions return heap information about all heap blocks of a given type, whether allocated or free. They return the size of the heap block that was allocated, excluding control structures and padding bytes. Borland C++ provides the heapwalk and farheapwalk functions that accomplish an objective similar to the Microsoft heapwalk functions. However, the Borland C++ heapwalk functions return heap information only about heap blocks that are currently allocated to your program. It also returns the size of the heap block including control structures and padding bytes. Recommended Actions: Substitute heapwalk function calls for Microsoft _heapwalk function calls, using heapwalk in place of either _heapwalk or _nheapwalk, and farheapwalk in place of either _fheapwalk or _bheapwalk. You may also have to change the logic of your program slightly to use these functions which are primarily an adjunct to debugging. The sample programs MFARHEAP.C and BFARHEAP.C show how this is done with a #define for _fheapwalk. msize functions. The Microsoft C6.0a msize functions, _msize, _bmsize, _fmsize, and _nmsize, return the size of a memory block allocated on the heap with a given pointer. Borland C++ has no similar function. Recommended Actions: Every time you allocate a memory block using one of the malloc functions or change its size with a realloc function, you will need to save and tabulate the number of bytes allocated, kept on a one-to-one basis with the pointer to the allocated memory. Then, change every reference to an msize function and its associated pointer argument to use the number of bytes previously allocated for that pointer. DO NOT use the Borland C++ heapwalk functions to find out the size of a memory block on the heap, because these functions return a value that includes the size of heap block control structure and any padding bytes. The sample programs MFARHEAP.C and BFARHEAP.C show how this might be done. Other Microsoft Based Heap Functions Microsoft C6.0a has other functions that allocate, reallocate and release memory from a based heap. These functions are _bcalloc, _bfree, _bmalloc, and _brealloc. The _bheapseg and _bfreeseg functions allocate and deallocate based heap segments, respectively. Borland C++ does not support the based heap, based pointers, and _segment variables. Recommended Actions: Remove all _bheapseg and _bfreeseg function calls, and all definitions of variables of the type _segment. Change all _based pointers to _far pointers. As a general rule when converting to Borland C++, substitute either the corresponding ANSI standard memory allocation function, or the corresponding Borland C++ far heap memory allocation function. You should use ANSI standard functions whenever possible to facilitate portability, as long as they permit you to manage memory as you need to do. Because all of the Microsoft C6.0a based heap functions take an additional segment variable as an argument, it is not straightforward to write a set of #define's to make the substitution. The sample programs BASE_BEF.C and BASE_AFT.C serve together as an example to show you how to convert programs that used based heap variables. freect The Microsoft _freect function inquires about the maximum number of items can be allocated on the near heap, where an item is a fixed number of bytes in size. _freect would typically be used in tiny, small or medium memory model Microsoft C programs. Borland C++ does not have a similar function, but it does have the coreleft function that returns the total number of bytes of unused memory at the top of the heap. Recommended Actions: Substitute the coreleft function for _freect. Compute the effective item size by adding six to the item size then round it up to the nearest multiple of 16. Finally, compute the maximum number of items that can be allocated by dividing the memory left by the effective item size, and pass this argument to coreleft. The Borland C++ heap management functions require a six byte control structure for each heap block. They always allocate a heap block on a paragraph boundary, demanding that the effective size allocated is an exact multiple of 16. Keeping Out of Heaps of Trouble Here are some other tips to help you work effectively with the Borland C++ heap manager. The Microsoft C _nheap family of functions map directly into the ANSI heap functions of Borland C++. The Microsoft C _fheap family of functions map directly to the Borland C++ farheap set of functions, as shown by the sample MFARHEAP.C and BFARHEAP.C programs. To have the greatest degree of portability and to guarantee defect- free program, whenever you reallocate heap space, always make sure that you use the current segment:offset value of a heap pointer returned by the heap manager. And, especially, be sure that any pointers derived from the pointer returned by the heap manager are all initialized to the latest value before use. Environments and tools The Borland C++ IDE is roughly the equivalent of the Programmer's Workbench, although naturally we think you'll find the IDE much easier to use. Chapter 3 of the Borland C++ User's Guide manual provides a complete reference to the IDE. The IDE loads its settings from two files: TCCONFIG.TC, the default configuration file, and a project file (.PRJ). TCCONFIG.TC contains general environmental information. The current project file contains information more specific to the application you're building. A project is the IDE's equivalent of a makefile. It includes the list of files to be built, as well as settings for the IDE options that control the compilation and linkage of that program. If you don't specify a project file when you start the IDE, a nameless project is opened and set with default compiler and linker options, but no file name list. Unlike Microsoft C, however, Borland C++ does not automatically create and run a makefile based on settings and file names that you give it in the project. If you want to use the IDE to set up a project, but use MAKE to do the actual build, then you can use the PRJ2MAK utility to convert a project file to a makefile. The following sections describe the significant differences between Borland C++'s MAKE, Project Manager, linker (TLINK), and command-line compiler (BCC) and Microsoft C's NMAKE, LINK, and CL. Paths for .h and .LIB files Microsoft C requires two environment variables, LIB and INCLUDE. The Microsoft C compiler uses INCLUDE to find standard header files. Similarly, the Microsoft linker uses the LIB variable to discover the location of the run-time libraries. Borland C++ does not use environment variables to store the paths for the library and the include files. Instead, you can easily set these paths in the IDE using the environment options. If you are working with the command-line compiler or the linker, you can use either command-line options or configuration files. Remember that even if you haven't opened a project, Borland C++ will store the paths in its default project file. When you install Borland C++, you are asked to set paths for include files and library files. Those paths become the default paths in the IDE. The include and library files paths are also written to the default command-line compiler configuration file TURBOC.CFG. The library path is written to the default standalone linker configuration file TLINK.CFG. In the IDE, you can change the default search paths for libraries and header files with the Options|Directories command. The settings in the Directories dialog box become a part of the current project. For the command-line compiler, you can change the search path for include and library files with the -I and -L options, respectively. These options can also be changed in the configuration file for the command-line compiler, TURBOC.CFG. The linker can use the /L option to set search paths for libraries and initialization code (like C0S.OBJ, the startup code for the small memory model). For instance, this option /LC:\BORLANDC\LIB;C:\WINAPPS\LIB tells the linker to look in the two paths named for library and initialization files. You can also create a TLINK.CFG file. TLINK.CFG is a regular text file that contains a list of valid TLINK options. For the Windows Resource Compiler, the -x option tells it to ignore the INCLUDE variable. In addition, you can specify an additional search path with the -i option ( -i all by itself does not imply -x).") When the Resource Compiler is invoked from the command line, it looks for windows.h on the path specified by the INCLUDE environment variable, if there is one. If that INCLUDE variable is set to some path other than the location of the windows.h supplied by Borland C++, your module might not be compiled correctly. (This does not occur in the IDE, because the IDE passes the correct information to the Resource Compiler.) For instance, if you have been using Microsoft C, then you probably have an INCLUDE environment variable set to the path of the Microsoft C header files. If you have also been using the Microsoft Windows SDK, then the version of windows.h included with the SDK is probably also in the INCLUDE directory. When you're building a Borland C++ application, the Resource Compiler should include the windows.h shipped with Borland C++. If you have a defined INCLUDE environment variable, then you should tell the Resource Compiler to ignore it with the -x option. (The same holds true for Microsoft C LIB environment variable, i.e. it contains both the standard C library path and the Windows library path, the latter only if you are writing for Windows and you have installed the Windows library in a path different than the standard MSC C libraries.) MAKE The version of MAKE supplied with Borland C++ 3.0 contains many new features, some of which are designed to increase compatibility with Microsoft's NMAKE. The new command-line switch -N turns on full NMAKE compatibility. See Chapter 2 of the Borland C++ Tools & Utilities Guide manual for more information on MAKE's options. The following list summarizes the differences between MAKE and NMAKE. NMAKE supports response files but MAKE doesn't. In NMAKE, you must surround strings to be compared with quotes. MAKE doesn't have this requirement; as long as the string to be compared doesn't contain spaces, you can compare them without quotes. NMAKE predefines several implicit rules; MAKE doesn't. However, the BUILTINS.MAK file contains several implicit rules that you can use without specifying them in the makefile. MAKE doesn't pass through environment variables. Command-line Compiler The following table lists comparable BCC and CL command-line compiler options. Some of the CPP (standalone preprocessor) options are listed. In many multi-pass compilers, a separate pass performs the work of the preprocessor, and the results of the pass can be examined. Since Borland C++ uses an integrated single-pass compiler, we provide the standalone utility CPP to supply the first-pass functionality found in other compilers. Note that most CL options that take arguments allow for a space between the option and the argument. BCC options that take arguments are usually immediately followed by the argument or list. CL and BCC options compared Microsoft C Borland C++ CL option BCC option What it does N/A @name Gives the command-line compiler a response file name. N/A +name Tell the command-line compiler to use the alternate configuration file name N/A -A ANSI keywords N/A -A-, -AT Borland C++ keywords (default) N/A -AK Use only Kernighan and Ritchie keywords. N/A -AU Use only UNIX keywords. /Zp2 -a Align word. /Zp1 -a- Align byte (default). /Aw, /Gw -WD Creates an .OBJ for Windows to be linked as a .DLL with all functions exportable. /Aw, /GW -WDE Creates an .OBJ for Windows to be linked as a .DLL with explicit export functions. /Ax -mx Use memory model x, where x is t, s, m, c, l, or h.. For BCC, following t, s, or m with ! tells compiler to assume DS != SS. /Bn N/A Use alt preprocessor CnL. N/A -B Compile and call the assembler to process inline assembly code. N/A -b Make enums word-sized (default) N/A -b- Make enums signed or unsigned. /C N/A Preserve comments in C preprocessor N/A -C Nested comments on. N/A -C- Nested comments off.(default) /c -c Compile to .OBJ but do not link. /Did -Dname Define 'name' to the string consisting of the null character. /Did=value -Dname=string Defines 'name' to 'string'. N/A -d Merge duplicate strings on. N/A -d- Merge duplicate strings off (default) (default). N/A -Ename Use filename as the assembler to use. /E CPP -P Preprocess source to standard output, include line numbers. /EP CPP -P- Preprocess source to standard output, without line numbers. N/A -f- Don't do floating point. N/A -ff Fast floating point (default). N/A -ff- Strict ANSI floating point N/A -ff- Strict ANSI floating point. N/A -f87 Use 8087 h/w instructions. N/A -f287 Use 80287 h/w instructions. /F hexnum N/A Sets stack size to hexnum bytes (hexnum must be hexadecimal). (By default) -Fc Generates COMDEFs. N\A -Fm Enables the -Fc, -Ff, and -Fs options. (By default) -Fs Make DS==SS for all memory models /Fa [file] N/A Create assembly listing. Name for list file defaults to Source.ASM. /Fb N/A Creates a bound executable file /Fc [file] -S Produces a combined source and assembly code listing. Name for list file defaults to Source.COD. /Fe file -efile 'file' names executable file. /Fl [file] N/A Creates object code list. Name for list file defaults to Source.COD. /Fm [file] -M Creates map file. Name defaults to Source.MAP, where source is the first source file specified. /Fo file -ofile 'file' names object file. /FPa N/A Generate floating-point calls; select alternate math library. /FPc -f Emulate floating point (default, coprocessor used if present at run time). /FPc87 N/A Selects 80x87 library (80x87 coprocessor must be present at run time). /FPi N/A Inlines 80x87 instructions; selects emulator library (coprocessor used if present at run time). /FPi87 -f87, -f287 Inlines 80x87 instructions; chooses coprocessor library (coprocessor must be present at run time). /F[file] N/A Generates standard PWB Source Browser database. /FR[file] N/A Generates extended PWB Source Browser database. /Fs [file] N/A Produce source list file. defaults to Source.LST. /Fx [file] N/A 'file' specifies a name for the MASM cross-reference file. G0 -1- Generate 8088/8086 instructions. G1 -1 Generate 80186 instructions. G2 -2 Generate 80286 protected-mode compatible instructions. /Gc -p Use Pascal calling convention. For CL, this is Pascal or FORTRAN, but they currently same calling convention. /Gd -p- Standard C calling conventions (default). /Ge -N Check for stack overflow. (Default for CL, but not for BCC). /Gi N/A Compile incrementally (for use with quick compile option /qc). /Gm N/A Store strings in CONST seg N/A -gn Stop compilation after n warning messages /Gr -pr Enables _fastcall to call conventions for functions (if possible, passing value in registers). /Gs -N- Turn off checking for stack overflow. (Off by default for BCC.) /Gt [number] -Ff[=size] Creates far variables automatically; 'size' or 'number' is threshold. /Gw -W Creates correct prolog/epilog for Windows program. For Borland C++, this creates an application with all functions exportable /GW -WE Generates prolog/epilog for explicit functions (marked with _export) in Windows program. N/A -H Causes the compiler to generate and use pre- compiled headers. N/A -H- Turns off generation and use of precompiled headers (default). N/A -Hu Tells the compiler to use but not generate precompiled headers. N/A -H=filename Sets the name of the file for precompiled headers. (By default) -h Use fast huge ptr math /H number -inumber Restricts length of external names to 'number'. /HELP BCC Calls QuickHelp. For help on BCC, simply invoke without options. N/A -in Make significant identifier length to be 'n'. /I dir -Ipath Directories for include files For CL, adds directory to the beginning of include file search directory list. N/A -jn Stop after 'n' compiler error messages. /J -K Changes default for char. from signed to unsigned. For Borland C++, -K- returns to signed. N/A -Jg Definitions for all template instances, and merge duplicates (default) N/A -Jgd Public definitions for all template instances N/A -Jgx External references for all template instances N/A -k Std stack frame on (default). N/A -Lpath Directories for libraries. /Lc,/Lr /Td Tells linker to create a real mode executable. /Li [number] N/A Use incremental linker, instead of standard linker. Number specifies byte boundary for padding near functions. /Lr See /Lc. /link opts -lopts Pass 'opts' to linker when invoked. N/A -l-option Suppress 'option' for the linker N/A -M Instruct the linker to create a map file. /MA option -Toption Pass 'option' to assembler when invoked. N/A -npath Set the output directory /NDdataseg -zRname Sets the data segment name. For BCC, option changes the name of the uninitialized data segment class to name. By default, the uninitialized data segments are assigned to class BSS. /NMmodule N/A Sets module name to 'module' /nologo N/A Don't print sign-on banner. /NTsegname -zCname Sets code segment name. This option changes the name of the code segment to 'name'. By default, the code segment is named _TEXT, except for the medium, large and huge models, where the name is filename_TEXT. (filename here is the source file name.) N/A -O Optimize jumps. N/A -O- No optimization (default). /O [options] (See comment) Provides optimization. For Borland C++, see specific options; for instance, -Z, -O, or -G. /Os -G- Optimize for size (default) /Os -O1 Optimize, smallest code /Ot -G Optimize for speed /Ot -O2 Optimize, fastest code /Oa -Oa Optimize, no pointer aliasing /Ow N/A no aliasing in function calls N/A -Ob Optimize, dead store elimination /Og -Oc Optimize, local common subexpression elimination /Od -Od Optimize, disable all optimizations /Oe -Oe Optimize, global register allocation, variable live range /Og -Og Optimize, global common subexpression elimination /Oi -Oi Optimize, intrinsic functions, automatic inlining /Ol -Ol Optimize, loop optimization /Ol -Om Optimize, loop invariants, code motion on /On N/A disable "unsafe" optimizations N/A -Op Optimize, copy propagation /Op N/A enable precision optimizations /Or N/A disable inline return /Os -Os Optimize, size of code /Ot -Ot Optimize, speed of .EXE /Ol -Ov Optimize, loop induction variable, strength reduction /Ox -Ox Optimize, speed: compatible with Microsoft compilers N/A -P Perform a C++ compile regardless of source file extension. N/A -Pext Perform a C++ compile and set the default extension to ext. N/A -P- Perform a C++ or C compile depending on source file extension (default). N/A -P-ext Perform a C++ or C compile depending on extension; set default extension to ext. N/A -p- Use C calling convention (default). /P CPP -P- -oname Preprocesses source file and sends output to name (CPP), or to Source.I (CL). N/A -Qe Instructs the compiler to use all available EMS memory (default). N/A -Qe- Instructs the compiler to not use any EMS memory. N/A -Qx Instructs the compiler to use all available extended memory. N/A -Qx=nnnn Instructs the compiler to reserve nnnn Kb of extended memory for other programs, and to use the rest itself. N/A -Qx=nnnn,yyyy Instructs the compiler to reserve 'nnnn' Kb of extended memory for other programs and 'yyyy' for itself. N/A -Qx=,yyyy Instructs the compiler to reserve 'yyyy' Kb of extended memory for itself. N/A -Qx- Instructs the compiler to not use any extended memory /qc N/A Invokes quick compile. N/A -R Generate ObjectBrowser information. N/A -r Use register variables on (default). N/A -r- Suppresses the use of register variables. N/A -rd Only allow declared register variables to be kept in registers. N/A -S Produce .ASM file /Sx option N/A Set options for source listing. Where 'x' is l, p, s, or t. N/A -T- Remove all previous assembler options. /Ta asm_src N/A Specifies that 'asm_src' be treated as an assembler source file. /Tc srcfile N/A Specifies that 'srcfile' be treated as a c source file. N/A -tDe Compiled and linked program is DOS .EXE file N/A -tDc Compiled and linked program is DOS .COM file N/A -tW Compiled and linked program is a Windows module using the -W options N/A -u Generate underscores (default) N/A -u- Disable underscores /u N/A Undefines all predefined identifiers /U Ident -UIdent Undefine any previous definitions of 'Ident'. N/A -V Smart C++ virtual tables. N/A -Va Pass class args by reference to temp variable N/A -Vb Backwards compatibility, virtual base class pointer N/A -Vc Backwards compatibility, no hidden members and code N/A -Vf C++ far virtual tables N/A -Vmv Member pointers have no restrictions N/A -Vmm Member pointers support multiple inheritance N/A -Vms Member pointers support single inheritance N/A -Vmd Use smallest representation for member pointers N/A -Vmp Honor declared precision for all member pointer types N/A -Vo Backwards compatibility, master switch turns on all N/A -Vp Backwards compatibility, pass 'this' to pascal member functions N/A -Vt Place virtual table pointer after non-static data members N/A -Vs Local C++ virtual tables. N/A -Vv Backwards compatibility, don't change layout of classes N/A -VmX C++ member pointers N/A -V0, -V1 External and Public C++ virtual tables. N/A -Vf Far C++ virtual tables. N/A -v Source debugging on N/A -v- Source debugging off N/A -vi, -vi- Controls expansion of inline functions. /V string N/A Copies 'string' to object file (for version control). N/A -w Display warnings on. N/A -wxxx Enable 'xxx' warning message. N/A -w-xxx Disable 'xxx' warning message. /w -w- Display warnings off. N/A -WS Creates an .OBJ for Windows that uses smart callbacks. /W n (See -w) Set warning level 0, 1, 2, 3, or 4. /WX -g1 Makes all warnings fatal. No object files are generated if warning occurs. (The -g option takes the form -gn, where n is the limit to number of warnings.) N/A -X Disable compiler autodependency output. /X N/A Ignore INCLUDE environment variable list of include search paths. N/A -Y Enable overlay code generation. N/A -Yo Overlay the compiled files. N/A -y Include line numbers in .OBJ for debugger N/A -y- Do not include line numbers in .OBJ for debugger N/A -Z Enable register usage optimization. N/A -zAname set Code class to 'name' N/A -zBname set BSS class to 'name' N/A -zDname set BSS segment to 'name' N/A -zEname set Far segment to 'name' N/A -zFname set Far class to 'name' N/A -zGname set BSS group to 'name' N/A -zHname set Far group to 'name' N/A -zPname set Code group to 'name' N/A -zSname set Data group to 'name' N/A -zTname set Data class to 'name' N/A -zX* Use default segment, class, or group name for X. /Za -A Enforces ANSI compatibility. Use only ANSI keywords. No vendor-specific extension allowed. /Zc N/A Ignores case for functions declared as _pascal. /Zd /y Generates line numbers for symbolic debugger. /Ze -A-, -AT Enable vendor-specific extensions. /Zg N/A Generates function prototypes; writes to standard output. /Zi /v For Microsoft, generates debugger information for CodeView. For Borland C++, generates information for IDE debugger and Turbo Debugger. /Zl N/A Library search records not written to object file. /Zpn -a, -a- Packs structure members on the 'n' byte boundary. 'n' can be 1, 2, or 4. /Zr N/A Generates checks for null pointers and far pointers that are out of range. /Zs files N/A Syntax check only. Command-line Options and Libraries The C0Fx.OBJ modules are provided for compatibility with source files intended for compilers from other vendors. The C0Fx.OBJ modules substitute for the C0x.OBJ modules; they are to be linked with DOS applications only, not Windows applications or DLLs. These initialization modules are written to alter the memory model such that the stack segment is inside the data segment. The appropriate C0Fx.OBJ module will be used automatically if you use either the -Fs or the -Fm command-line compiler option. The -Fc (generate COMDEFs), -Ff (create far variables), -Fs (assume DS == SS in all models), and -Fm (enable all -Fx options) command-line compiler options are provided for Microsoft compatibility. These options are documented in full in Chapter 5 of the Borland C++ User's Guide manual. Linker The Borland C++ linker, TLINK, is invoked automatically from the command- line compiler unless the -c compiler option is used. Options such as memory model and target (Windows or DOS), are passed from the compiler to TLINK; TLINK links the appropriate libraries based on the compile options. TLINK can be used to build both DOS and Windows programs. See Chapter 4 in the Borland C++ Tools & Utilities Guide manual for material on module definition file statements. The following table compares TLINK and LINK options. Note that Borland C++ TLINK options are case-sensitive, while Microsoft LINK options are not. LINK and TLINK options compared Microsoft C Borland C++ Link option TLINK option What it does N/A /3 Enable 32-bit processing. /A:size /A=nnnn Specify segment alignment for Windows images. /BA N/A BATCH. Suppresses prompts for library or object files not found. N/A /C Treat EXPORTS and IMPORTS section of module definition file as case sensitive. /CO /v Include full symbolic debug information. /CP:bytes N/A Sets the program's maximum memory allocation to 'bytes'. N/A /d Warn if duplicate symbols in libraries. /DOSSEG (See comment) For assembly programs, forces a certain ordering of segments in executable. To enable DOSSEG for an assembly program, include DOSSEG in the source code. /DS N/A For assembly programs, tells linker to load data starting at high end of DS instead of low end. /E N/A Packs the executable by removing repeated series of bytes. /F By default For LINK, tells linker to optimize far calls to procedures in same segment as caller. (Used with MS /PACKCODE option.) For TLINK optimizes far calls automatically. /HE /? Provides help on command-line options. /HI N/A For real-mode assembly programs, places executable as high in memory as possible. N/A /i Initialize all segments. /INC N/A Prepares for ILINK. /INF N/A Tells LINK to display link information while in process. N/A /Lpaths Specify library search paths. /LI /l Include source line numbers and associated addresses in map file. /M /m Create map file with public global symbols. /NOD [:name] /n Don't use default libraries. /NOE /e Ignore Extended Dictionary. /NOF N/A Turns off far call translation (see /F option) /NOI /c Treat case as significant in symbols. /NOL N/A Suppress banner /NON N/A Arrange segments in executable in the same order as they are arranged by /DOSSEG. /NOP /P- Turn off code packing. N/A /o Overlay following modules or libraries. Microsoft LINK uses parentheses around files to be overlaid. (Note that the overlay scheme is different between products.) /O:number N/A Set interrupt 'number' for passing control to overlays (other than the default 63). /PACKC[:n] /P=n Pack code segments. 'n' specifies maximum size of groups formed by /PACKC or /P. /PACKD[:n] N/A Pack data segments. 'n' specifies maximum size of groups formed by /PACKD. /PADC:size N/A Tells LINK to pad code module for ILINK by 'size' bytes. /PADD:size N/A Tells LINK to pad data segments by 'size' bytes. /PAU N/A Pauses linking. /PM:type N/A Sets window type for Presentation Manager. /Q N/A Produces Quick library. N/A /s Create detailed map of segments. /SE:number N/A Sets maximum number of segments allowed. /ST:number N/A Sets stack size. /T /t Produce .COM files. N/A /Td Create target DOS executable. N/A /Tdc Create target DOS .COM file. N/A /Tde Create target DOS .EXE file. N/A /Tw Create target Windows executable (.DLL or .EXE). N/A /Twe Create target Windows application (.EXE). N/A /Twd Create target Windows DLL (.DLL). /W N/A Warn fixups. N/A /x Don't create map file. N/A /ye Use expanded memory for swapping. N/A /yx Use extended memory for swapping. Converting Microsoft DOS Graphics Functions The differences between the Microsoft C6.0a DOS graphics system and the Borland Graphics Interface are summarized for your reference below. Two sample programs, MSCGRF.C and BGIGRF.C, provide you with a comparison between Microsoft C6.0a and Borland C++ graphics. You will find them helpful as a reference as you convert Microsoft C graphics programs to run with the Borland C++ BGI. These programs are available for download (see the appendix for more details). Supported Graphics Adapters Microsoft C6.0a is a closed-ended graphics system that supports a limited set of graphics cards. There is no public specification from Microsoft explaining how to add support for other graphics drivers. Graphics adapters recognized automatically by Microsoft C6.0a graphics are Video Graphics Array (VGA), Extended Graphics Adapter (EGA), Color Graphics Adapter (CGA), Multicolor Graphics Array (MCGA), and the Olivetti/AT&T variations of the first three standards. In addition, if you run the Microsoft-supplied terminate-and-stay-resident (TSR) program, MSHERC, Microsoft's graphics recognizes and supports video adapters compatible with the Hercules monochrome graphics hardware specification. If you develop software for use by others, you must require your users to run MSHERC before running your Microsoft C graphics programs with a Hercules monochrome graphics adapter. MSHERC occupies nearly 7K bytes of memory, and cannot be removed from memory once installed. The Microsoft C _getvideoconfig function returns information about the current graphics adapter, and the _setvideomode function sets up the adapter in an appropriate graphics mode. The Borland Graphics Interface (BGI) is an open-ended graphics system that supports industry standard graphics adapters. Available from Borland is a specification that describes the BGI and how to develop third-party BGI graphics drivers. The BGI automatically recognizes and supports VGA, EGA, CGA, IBM PC 3270, Olivetti/AT&T CGA, and Hercules monochrome graphics adapters. If an IBM 8514 Application Interface (AI) TSR is installed on a PC with an IBM 8514 or compatible graphics adapter, the BGI recognizes and supports this device, in conformance with IBM's recommendations for 8514 programming. In addition to the BGI graphics drivers supplied with Borland C++ 3.0, third-party BGI drivers have been developed to support various VGA chip sets operating in Super VGA graphics modes that offer higher resolution and/or more colors than standard VGA. The Borland CompuServe Forum always contains information about currently available BGI drivers. With Borland C++, the initgraph function loads a graphics driver from disk and puts the graphics system into graphics mode. It is generally the first BGI function that your program calls. You may also use the detectgraph function to override the graphics mode selected by initgraph. If you or users of your software have a third-party BGI graphics driver available, your program would first use the registerbgidriver function to register it for use by BGI, and then call initgraph. Make sure that your program can access the BGI drivers that it needs to use. The third argument to the initgraph function gives the path where your program finds all of the BGI drivers it can use. Relying on just the initgraph function is the simplest for you to program, but it may complicate the installation of your software. You may also add BGI drivers to the GRAPHICS.LIB library supplied with Borland C++, link them into your program, then register them for use by your program with the registerbgidriver function. These steps simplify installation of your software, but add to the amount of memory required by your program. See the on-line help in the IDE and the documentation file UTIL.DOC for more information about this treatment of BGI drivers. Displaying Fonts Microsoft C6.0a provides two types of graphics fonts, fixed height bitmapped fonts and scalable vector fonts. It also has special functions to display the built-in video BIOS bitmapped font for the current graphics mode. Microsoft graphics manages the BIOS font differently than the graphics fonts. The Microsoft bitmapped fonts are in three typeface families: fixed width Courier, sans serif proportional Helv, and serif proportional Times Roman. The scalable vector fonts are Modern, a narrow sans serif proportional font; Script, a handwriting-like font; and Roman, a Times Roman look-alike. The Microsoft bitmapped fonts cannot be resized. If you want to use a specific bitmapped font, it is best if your program builds a table of available fonts and their characteristics obtained by calls to the _getfontinfo function. Then it can build a text string describing the exact attributes of the required font, and select the font with the _setfont function. The Microsoft scalable fonts can be displayed at any size. In addition, you can display a scalable font at any horizontal to vertical ratio. The Microsoft C6.0a graphics library does not have any functions to justify text at the left, center, right, top, middle, or bottom of a rectangular area. As a consequence, your program must manage each step of the process: calculation of text width and height, status of justification attributes, computation of starting x-y text coordinate including justification, and, finally, the actual display of the text. To use Microsoft graphics fonts, your program must read them from the directory passed to the _registerfonts function. Borland C++ includes eleven vector fonts of the sans serif, serif, and ornamental varieties. The default font is an 8x8 pixel sans serif font that can be resized in integral multiples of 8 pixels using the settextsize function. You can resize all of the other fonts to various sizes by using the settextsize function. You can establish the horizontal-vertical ratio for displaying text with the setusercharsize function. The default horizontal-vertical ratio is one-to-one (1:1). The Borland C++ settextjustify function sets up the rules used to justify text. Once set up, text justification is done automatically by the outtextxy function with respect to the current graphics position. To use Borland C++ graphics fonts, your program must read them from the same directory in which the BGI drivers are found. Alternately, you can link BGI fonts into your program, registering and using them much like any BGI drivers you may have linked into your program. You can register a font for use by your program with the registerbgifont function. See the on-line help in the IDE and the documentation file UTIL.DOC for more information about treating BGI fonts in this fashion. Finally, the Borland C++ 8x8 default font displayed at a 1:1 horizontal- vertical ratio offers the best fit for replacing the built-in BIOS bitmapped font displayed by the Microsoft C6.0a functions _outmem and _outtext. Note though that the sizes of the BIOS fonts vary: CGA is 8x8, EGA is 8x14, Hercules is 9x14, and VGA is 8x16. The State of the Graphics System Microsoft C6.0a does not have a complete set of function calls to determine the current state of the graphics system. As a result, you must keep track of the graphics system state yourself in your programs, saving old and new state of each graphics attribute when you set it. However, the following graphics state information is maintained by Microsoft C graphics: x-y coordinates, foreground color, background color, fill pattern, line pattern, font characteristics, font orientation, and line drawing mode. Borland C++ has a complete set of function calls to return the current state of each attribute in the graphics system. These include graphics mode, palette, x-y coordinates, foreground color, background color, palette, aspect ratio, fill pattern and color, line pattern and color, font characteristics, font orientation, and viewport settings. Graphics Coordinate Systems Microsoft C graphics have three types of functions for displaying graphic objects: physical coordinates, viewport coordinates, and two types of windowed coordinates. Physical coordinates serve only as absolute physical reference points for graphics operations; they are not used by any graphics functions that draw on the screen. Microsoft viewport coordinates are integer x-y values plotted with respect to the zero point of the current window, as set with the _setviewport function. The _outgtext function displays text using the current viewport coordinates. Microsoft windowed coordinates are floating point x-y values set up with the _setwindow function, and may be positive or negative numbers. Both _setviewport and _setwindow establish the rectangular boundaries of a window using the upper left and lower right corners of the rectangle. If you use windowed coordinates for drawing graphic objects, you must also transform these coordinates into viewport coordinates to display text with your graph. Use either _getviewcoord_wxy or _getviewcoord_w to do this. The shape drawing functions draw lines, rectangles, arcs, and polygons, get images from the screen, and put images onto the screen. Each function that uses viewpoint coordinates has one or two analogous functions in the windowed coordinate system. For example, _arc draws an arc with viewport coordinates, while _arc_wxy draw an arc in windowed coordinates. The _ellipse function draws an ellipse using viewport coordinates, and both _ellipse_w and _ellipse_wxy use windowed coordinates. The windowed functions with the suffix _w accept coordinate arguments with four distinct x-y values, while those with the suffix _wxy take structures of x-y coordinate pairs as arguments. Microsoft C graphics provides the _getphyscoord, _getviewcoord, _getviewcoord_w, _getviewcoord_wxy, and _getwindowcoord functions to map from one coordinate system to another, which is required uses windowed graphics functions. Borland C++ offers a unified view of graphics with a single set of functions that all use viewport coordinates as a single frame of reference. After the viewport is set, all functions operate relative to the zero x-y coordinate of the viewport. Other Things You Must Do Differently Microsoft C 6.0a graphics has no predefined bitmap patterns for filling shapes or drawing lines. You must design and describe bitmap patterns in your program before using them. Microsoft C graphics also does not have any parameter to control the width of lines drawn. In the Microsoft graphics system, if you need to draw a line more than one pixel wide, you accomplish this by drawing several lines one pixel apart from each other until the resulting line is wide enough. Borland C++ allows you to use its built-in bitmap patterns to fill shapes and to draw lines, and to define and use your own. You can also vary the widths of lines drawn by the arc, rectangle, pie, drawpoly, line, and linerel, or ellipse functions. Microsoft C6.0a graphics employs the concept of a bounding rectangle, a rectangle drawn so that it contains a drawn ellipse, or the ellipse from which a drawn shape is derived. A bounding rectangle touches an ellipse or circle at exactly four points, the vertices of the figure. For an arc or pie, the endpoints of the drawn shape are marked by lines that intersect the bounding rectangle. To draw a curved shape, you need to compute the upper left and lower right of corners of its bounding rectangle from its center point and radii. The Borland C++ graphics system uses a simple and intuitive system for drawing curved shapes. You need only to describe the center point of the shape in x-y coordinates, and the radii. To draw either an arc or pie shape, you also need to specify the starting and ending angles of the endpoints, stated in degrees. The Microsoft C graphics function _setwritemode controls the logical line drawing mode used for _putimage, _lineto, _polygon, and _rectangle operations. The manifest constants _GAND, _GOR, _GPRESET, _GPSET, and _GXOR provide different ways to combine the result of from the current drawing operation with the data already on screen. The results are less than intuitive, as shown by the pair of graphic programs BGIGRF.C and MSCGRF.C. Borland C++ uses logical operators to control only the putimage function. A Graphics Reference for Microsoft C Users Here is a reference of graphics functions to help you convert your Microsoft C graphics programs. BGI contains many other useful graphics functions. This reference tabulates the BGI functions that most closely correspond to Microsoft C graphics functions. They are listed in alphabetic order by category of graphics function. Graphics System Control Microsoft C Borland BGI _getactivepage N/A, maintain in your program _getvideoconfig detectgraph, initgraph, getaspectratio,getpalette, getmaxx, getmaxy _getvisualpage N/A, maintain in your program _setactivepage setactivepage _setvideomode setgraphmode _setvideomoderows No equivalent, uses BIOS font _setvisualpage setvisualpage Drawing & Filling Microsoft C Borland BGI _arc arc _ellipse ellipse or fillellipse _floodfill floodfill _getarcinfo getarccoords [arc only] _getcurrentposition getx & gety _getcurrentposition_w No equivalent, remap to viewport coordinates and use getx and gety _getfillmask getfillpattern _getlinestyle getlinesettings [line style, pattern, & thickness] _getwritemode N/A _lineto lineto _moveto moveto _pie pieslice _polygon drawpoly or fillpoly _rectangle rectangle _setfillmask setfillpattern _setlinestyle setlinestyle [line style, pattern, & thickness] _setwritemode raster operations (ROPS) are used as arguments to putimage Text Output Microsoft C Borland BGI _displaycursor No equivalent, used in text mode _getfontinfo gettextsettings _getgtextextent textwidth _getgtextvector No equivalent, maintain this information in your program _gettextcolor No equivalent, uses BIOS font _gettextcursor No equivalent, used in text mode _gettextposition No equivalent, uses BIOS font _gettextwindow No equivalent, uses BIOS font _outgtext outtext _outmem No equivalent, uses BIOS font _outtext No equivalent, uses BIOS font _registerfonts registerbgifont _scrolltextwindow No equivalent, uses BIOS font _setfont settextstyle & setusercharsize _setgtextvector settextstyle _settextcolor No equivalent, uses BIOS font _settextcursor No equivalent, used in text mode _settextposition No equivalent, uses BIOS font _settextrows No equivalent, uses BIOS font _settextwindow No equivalent, uses BIOS font _unregisterfonts No equivalent _wrapon No equivalent, controls word wrap for _outtext] Screen, Viewport & Window Microsoft C Borland BGI _clearscreen cleardevice or clearviewport _getimage getimage _getphyscoord No equivalent, view(x,y) --> physical (x,y) _getpixel getpixel _getviewcoord No equivalent, physical (x,y) --> view(x,y) _getviewcoord_w No equivalent, window (wx,wy) --> view(x,y) _getviewcoord_wxy No equivalent, window (wx,wy) --> view(x,y) _getwindowcoord No equivalent, view(x,y) --> window(wx,wy) _imagesize imagesize _putimage putimage _setcliprgn setviewport [also viewport] _setpixel setpixel _setvieworg setviewport [window & clip, too] _setviewport setviewport [also clip] _setwindow Window coordinates are not available Color Control Microsoft C Borland BGI _getbkcolor getbkcolor _getcolor getcolor _remappalette setpalette _remapallpalette setallpalette _selectpalette [Not available, CGA only] _setbkcolor setbkcolor _setcolor setcolor State Query & Error Handling Microsoft C Borland BGI _grstatus graphresult & grapherrormsg