16.3 Using Memory Models

A Windows application is like an MS-DOS application in that it may have one or more code segments and one or more data segments. The memory model, which you specify when you compile your source-code modules, determines whether compiler-generated instructions use near or far addresses. If you use a memory model that specifies only one code or data segment, the compiler generates instructions that employ near (16-bit) addresses for, respectively, code or data references. If you compile by using a memory model that specifies multiple code or data segments, the compiler generates instructions that use far (32-bit) addresses for code or data references. The following figure shows how the memory model affects the way an application addresses code and data:

There are two memory models, large and huge, for compiling a module that generates far addresses for both code and data references. In the large memory model, far pointers can be incremented only within the 64K offset range of a segment. In the huge memory model, far pointers can be incremented across 64K boundaries, causing both the segment address and the offset to be incremented. Also, if a module is compiled with the large memory model, Windows will be able to load only one instance of the module.

Ideally, a Windows application will use the medium model, and the size of its modules will be 8K or less. The module that initializes the application should be marked PRELOAD and DISCARDABLE in the .DEF file. The module that processes the message queue should be marked PRELOAD. All other modules should be marked LOADONCALL and DISCARDABLE. An application that follows these guidelines will start faster and consume fewer system resources.

If you are using CL, compile your Windows application's C-language source-code modules, using the /AS option for the small model or the /AM option for the medium model.

You can also use a mixed memory model. For a mixed model, you compile modules by using the /AS option, assign the same code-segment name to those modules whose code segments you want to group together, and assign different code-segment names to those modules for which you want to generate different code segments. To assign a code-segment name to a module, use the CL option /NT. A function that is called from a different code segment must be declared as a far function in the module where the call is made, as in the following example:

UINT FAR PASCAL FuncInAnotherCodeSeg(UINT, LONG);
UINT uReturn;
        .
        .
        .

uReturn = FuncInAnotherCodeSeg(0, 0L);

The advantage of using the mixed memory model is that you need only define calls made between code segments as FAR. Functions that are declared FAR increase code size and require more machine cycles to be called.

For another form of the mixed memory model, you can compile modules with the /AM option, which makes function calls FAR by default. Then, instead of declaring FAR functions, you prototype as NEAR those functions that are called only within the same segment. The disadvantage of this method is that all C run-time library functions will also be FAR functions.