__cs, __far, __handle, __huge, __near, __ss, __interruptThese keywords provide support for mixed language programming and for mixed memory models. Although they are not necessary for all applications, their judicious use can significantly enhance program performance.
Note: The keywords __far, __interrupt, __handle, __loadds, and __huge are ignored by default in compilations using the Win32 (-mn) memory model. Ignore these keywords in any compilation by specifying the -NF compiler option.
As with other pointer modifiers, __handle is placed immediately before the * in a pointer type description. For example:
int __handle *ptr;For more information, see Using Handle Pointers.
Note: Digital Mars C++ does not support the Huge memory model.
For more information see Choosing a Memory Model.
int __far *p; // p is a <far pointer to><int> int * __far *p; // p is a <far pointer to><pointer to>< int>The __near and __far keywords are right-associative. In other words, they associate with the * on their right. Remember that <pointer to> becomes <near pointer to> for the Tiny, Small, Medium, DOSX, and Phar Lap models, and a <far pointer to> for the Compact, and Large models.
#include <dos.h> char __near *np, __far *fp; np = (char __near *) fp;Note: FP_SEG(fp) must equal DS!
Convert a near pointer to far pointer as follows:
#include <dos.h> char __near *np, __far *fp; fp = MK_FP(getDS(), (unsigned)np);Notice how the value of DS is obtained for constructing the __far pointer.
int * const p; // const pointer to int int __handle * p; // handle pointer to int int * const *p; // pointer to a const pointer to int int * __far *p; // far pointer to a pointer to intA declaration with the specifier volatile tells the compiler that the declared object changes in an undetectable way. These objects are not optimized.
ARM p. 110, Gray p. 521
The sizes of these pointer types are different and will depend on the memory model in use. For more information, see the section "Sizes and Addressability of Pointers" later in this chapter.
For more information see Choosing a Memory Model.
Interrupt functions should not be inline or non-static member functions.
An interrupt function saves all the registers on the stack, reloads DS from DGROUP (so that global variables in the data segment can be accessed), and enables interrupts. At the end of the function, the registers are restored and an IRET instruction is executed.
An interrupt function is normally declared as:
void __interrupt isr(void);or:
void __interrupt isr( unsigned es, unsigned ds, unsigned di, unsigned si, unsigned bp, unsigned sp, unsigned bx, unsigned dx, unsigned cx, unsigned ax, unsigned ip, unsigned cs, unsigned flags);The second form allows access to the values the flags and registers had when the interrupt occurred.
Modifying these variables causes the corresponding register to have the modified value upon returning from the function. Be very sure of what you are doing if you modify the bp, sp, ip, cs or flags registers.
The SS, FS and GS registers are not saved; if they need to be, use the inline assembler to save and restore them. The floating-point registers on the numeric coprocessor are not saved automatically either.
Since an interrupt function sets the values of the registers upon function exit, using a:
return exp;statement will not have the expected effect. To return a value, set the appropriate register( s) to the value.
Do not call an interrupt function and pass parameters to it. To pass values to it, place the values into registers with the inline assembler, and then access the register values from within the interrupt function using the second form of the declaration above. If you do pass parameters, they will appear after the "flags" parameter.
If the interrupt function will be using a significant amount of stack, it may be necessary to switch to a separate stack of a known size. This can be done with the inline assembler. Note also that in small and medium model programs, SS will not be the same as DS inside the interrupt function.
Some guidelines for writing interrupt functions:
// Remove extended keywords for non Digital Mars // compilers #if !defined(__DMC__) #define __far #define __near #define __cs #define __ss #define __handle #endif
For information on using different pointer types, see Choosing a Memory Model.
For near references to be correct when the processor is in real mode, the segment register DS must contain the correct segment value for data pointers. When the processor is in protected mode, the segment register must contain the correct selector value. CS contains the segment value for function pointers.
Near pointers are used for function pointers in the Tiny, Small, and compact models. Near pointers are the default in the Tiny, Small, and Medium memory models for data pointers.
In the 32-bit memory models (NT, DOSX, and Phar Lap), near pointers can be used to access any location within a 4GB segment. Each near pointer requires four bytes of storage to hold the offset. For near references to be correct, the segment register DS must contain the correct selector for data pointers. For function pointers, CS must contain the selector, rather than DS. Near pointers are the default for both code and data in 32-bit memory models.
In 32-bit memory models, far pointers require six bytes: a two-byte selector and a four-byte offset. The selector is an index into the Global Descriptor Table. This index is put into the appropriate segment register. The offset provides an offset within the selected memory segment. In 32-bit programming, far pointers are only useful when working at operating system level.
Note: Never use far pointers when compiling with the NT (-mn) memory model.
When applied to a pointer, the __ss keyword is used exactly the same way as the __near keyword. However, the compiler generates code to ensure that the current segment address is set to the stack segment rather than the data segment. Consequently, __ss pointers are relative to the SS segment register as opposed to near pointers, which are relative to DS. If SS == DS, as in the Tiny, Small, Medium, DOSX, and Phar Lap models, then there is no difference between __ss pointers and near pointers, except for type checking. In the Compact and Large models, or if SS != DS, then __ss pointers can be used only to point to parameters and automatic variables. Under the same conditions, near pointers can point only to static and global data. (SS==CS==DS==ES at all times for programs compiled for the NT memory model.)
Some specialized applications require use of the Small or Medium memory models but also require that SS != DS. Similarly, SS != DS in applications which are put into ROM, Microsoft Windows applications, or routines for OS/ 2 dynamic link libraries, even when the Small and Medium memory models are used.
Force SS!=DS by appending a w to the -mmodel compiler option, for instance -msw. The __ss pointer then becomes quite important as auto variables can be accessed via two-byte __ss pointers rather than four-byte far pointers.
void func() { static int darray[10];// array in data seg int __near *pd; // pointer into data seg int sarray[10]; // array in stack seg int __ss *ps; // pointer into stack seg ps = sarray; for (pd = darray; pd &darray[10]; pd++, ps++) *ps = *pd; pd = sarray; // Error: near pointer cannot access stack ps = darray; // Error: vice versa }Far pointers are useful in accessing specific memory locations in the computer. The video display memory from the Small model is one example:
#include <dos.h> unsigned short __far *pvideo; int i; /* Point into mono display ram */ pvideo = (unsigned short __far *) MK_FP(0xB000,0); /* Clear screen */ for (i = 0; i< 25 * 80; i++) pvideo[i] = 0x0700 + ' ';
int (__near *fp)();A far pointer to a far Pascal function returning char is declared with:
char (__far __pascal *fp)();Due to limitations of this syntax, it is impossible to declare constructs such as a near pointer to a far function or a far pointer to a near function. The compiler always selects the function type according to the type of pointer. This compiler selection cannot be overridden.
For more information on mixing pointer types, see Mixing Languages.