Function Attributes

The optional attributes nonterminal allows you to override default addressing modes by specifying a different memory model, or to select a calling convention on a per-function basis to override the defaults. You can also specify functions as __fastcall, __export, __inline, __based, inline assembler, or __interrupt, and can specify register-handling with __loadds and __saveregs.

Specifying Function Addressing (Microsoft Specific)

By using the special keywords __near, __far, __huge, and __based, you can override the addressing specified by the compile-time memory models. The following list summarizes use of these keywords in function attributes.

__near

Functions are assumed to be in the default code segment (_TEXT). The function is referenced with 16-bit addresses (pointers to functions are 16 bits) and can be called only by functions in the same code segment. Functions declared as __near can be allocated in other segments by declaring them as __based or using the /NT compilation option.

32-Bit Specific

The use of the __near keyword is not allowed for 32-bit targets.¨

__far

Functions are not assumed to be in the current code segment. Far objects are referenced with 32-bit addresses (pointers to functions are 32 bits) and can be called with a far call by functions anywhere in memory. Functions in the same compilation unit reside in the same segment unless the alloc_text pragma is used, or unless the function is declared as based.

32-Bit Specific

The use of the __far keyword is not allowed for 32-bit targets.¨

__based

Specifies that a function resides in a specified segment. More information on __based appears later in this section.

__huge

The __huge keyword is not applicable to functions.

This example uses the __far keyword:

void __far handler( unsigned doserr, unsigned __far *bdr );

The default for Microsoft C is that the Microsoft extensions are enabled. Use the /Za command-line option to disable these extensions.

Specifying Calling Conventions (Microsoft Specific)

The special keywords discussed in this section allow you to directly specify the calling convention for any function. This list summarizes these Microsoft-specific keywords.

__cdecl

Specifies that the associated function is to be called using the normal C calling convention (arguments are pushed from right to left, the calling function adjusts the stack, and no case translation takes place). This modifier is placed before the function name, and can appear before or after the __near and __far modifiers. The /Gd command-line option forces the __cdecl calling convention.

__pascal, __fortran

Specifies that the associated function is to be called using the Pascal or FORTRAN calling convention (arguments are pushed from left to right, the called function adjusts the stack, and identifier names are translated to uppercase). These modifiers are placed before the function name, and can appear before or after the __near and __far modifiers. The __fortran and __pascal modifiers are synonyms. The /Gc command-line option forces the __pascal or __fortran calling convention.

32-Bit Specific

The __fortran and __pascal keywords are not supported for 32-bit targets. ¨

__fastcall

Specifies that the function uses a calling convention that passes arguments in registers rather than on the stack, resulting in faster code for small functions. Arguments are passed from left to right, the called function adjusts the stack, and no case translation takes place. Using /Gr on the command line causes each function in the module to compile as fastcall unless the function is declared with a conflicting attribute, or the name of the function is main. See the next section, “Fastcall Functions,” for more information.

__stdcall

Specifies that the arguments of the designated function are pushed from right to left, that an underscore is prepended to the name, and @### is appended, where ### is the number of bytes in the parameters of the function. This appended “name decoration” allows link-time argument checking to be done. The called function does its own stack adjustment when it returns to the caller. Functions declared with __stdcall return values the same way as functions declared using __cdecl. If a __stdcall function has a variable number of arguments, it must have a prototype and it will be implemented as __cdecl. The /Gz command-line option specifies __stdcall for all functions that are not explicitly declared with a different calling convention.

32-Bit Specific

The __stdcall calling convention is only available to 32-bit compilations.¨

This example declaration specifies the __cdecl calling convention:

int __cdecl compare( unsigned *key );

Fastcall Functions (Microsoft Specific)

A __fastcall function in programs for 16-bit targets receives up to three 16-bit arguments passed in registers rather than on the stack. The choice of registers for the __fastcall calling convention depends on the type of arguments:

Type Register Candidates

char / unsigned char AL, DL, BL
int / unsigned int AX, DX, BX
long / unsigned long DX:AX
near pointer BX, AX, DX
far or huge pointer Passed on the stack

Arguments are allocated to suitable registers if available and are pushed onto the stack otherwise. Structures, unions, and all floating-point types are always pushed onto the stack. Return values of four bytes or smaller, including structures and unions, are placed in the registers as follows:

Size Register

1 byte AL
2 bytes AX
4 bytes DX:AX

The implementation of fastcall functions is processor-dependent. On the 8086 and 80286, floating-point values are returned on the floating-point stack. To return structures or unions larger than four bytes, the calling program pushes a hidden last parameter, which is a near pointer to a buffer in which the value is to be returned. A far pointer to the hidden-parameter must be returned in DX:AX.

For the 80386 and 80486 processors, the first two arguments that have integer or pointer types are passed in the ECX and EDX registers, regardless of size. The rest of the arguments are passed on the stack from left to right. Regardless of length, structure returns are handled with a hidden parameter.

The treatment of character arguments depends further on prototypes. If there is no prototype, the argument is promoted to short and the rules for short integers apply. Only if the argument is prototyped to type char do the character rules apply.

The __fastcall calling convention cannot be used with functions having variable-length parameter lists, or functions having any of the following attributes: __cdecl, __export, __fortran, __interrupt, __pascal, __saveregs.

Note:

Microsoft does not guarantee its implementation of the fastcall calling convention between releases.

Export Functions (Microsoft Specific)

The __export keyword allows you to specify that a function is to be exported from a dynamic-link library (DLL) to Windows. Use this form to specify an exported function:

__export declarator

The declarator is the name of the exported function. When a function is declared as __export, the compiler places information in the object file to show that the function is exported from a DLL. Functions, operators, and data can be declared as __export.

The main use for __export is to export symbols that reside in a DLL. You also may need to export event-handler functions for Microsoft Windows programs, or for PWB extensions.

The __export keyword does not eliminate the need for a module-definition (.DEF) file when building a DLL. If you declare a symbol as __export and no .DEF file entry exists for that symbol, the linker assumes that the symbol has the following characteristics:

No input/output (I/O) privilege

Shared data

Not resident

No alias name

If these default characteristics are satisfactory, the symbol does not require an entry in a module-definition file. Otherwise, you must create an EXPORTS entry in the module-definition file for the symbol to specify these characteristics.

The __export keyword also causes the compiler to enter the size, in words, of the function's parameters into the export record of the object module. This size information corresponds to the pwords field of an EXPORTS statement that is in a module-definition file. You cannot override the size information in the export record with an EXPORTS entry in the .DEF file.

If you have an EXPORTS entry for a function, the pwords field in the .DEF file should be set either to 0 (which tells the linker to use the value given by the compiler) or to the same value given by the compiler. The pwords field is ignored unless you also request I/O privilege. For more information on creating .DEF files and import libraries, see Chapters 16 and 22, respectively, in the Environment and Tools manual.

The following statement declares funcsample as a far Pascal function that takes a single argument of any pointer type and does not return a value.

void __export __far __pascal funcsample( void *s );

The presence of __export causes the function to be exported. A .DEF file is still required for the program.

Inline Functions (Microsoft Specific)

The __inline keyword tells the compiler that it can substitute the code within the function definition for every instance of a function call. Substitution occurs at the discretion of the compiler. Use this form to specify an inline function:

__inline type opt function_definition;

The use of inline functions generates faster code and can sometimes generate smaller code than the equivalent function call generates for the following reasons:

It saves the time required to execute function calls.

Small inline functions, perhaps three lines or less, create less code than the equivalent function call because the compiler doesn't generate code to handle arguments and a return value.

Functions generated inline are subject to code optimizations not available to normal functions because the compiler does not perform interprocedural optimizations.

Functions using __inline should not be confused with inline assembler code. See “Inline Assembler” for more information.

Function Addressing Using __based (Microsoft Specific)

If a function is to be allocated in a given segment, it can be declared as based on a segment constant. The base for a function can be specified as

__based(__segname( string-literal ) )

A function declared as __based resides in the code segment named by string-literal. The built-in function __segname accepts a string enclosed in quotation marks and returns a value of type __segment. The __segment type specifies the segment in which the based function resides. You can use the __near or __far keyword with the __based keyword when declaring a function.

In programs that use overlays, you can reduce swapping by using __based to group functions that frequently call one another. You also can use __based to ensure that near functions reside in the same segment as the functions that call them.

Declaring functions as __based replaces the alloc_text pragma. However, the alloc_text pragma is retained for backward compatibility.

The base for a function based in a segment can also be specified as

(__based)__self

The __self function ensures that the function's location is the segment in which the pointer itself is stored. Such pointers can save space in a linked list or tree if the entire data structure fits in a single segment.

Inline Assembler (Microsoft Specific)

The inline assembler lets you embed assembly-language instructions directly in your C source programs without extra assembly and link steps. The inline assembler is built into the compiler—you don't need a separate assembler such as the Microsoft Macro Assembler (MASM).

Because the inline assembler doesn't require separate assembly and link steps, it is more convenient than a separate assembler. Inline assembly code can use any C variable or function name that is in scope, so it is easy to integrate it with your program's C code. And because the assembly code can be mixed with C statements, it can do tasks that are cumbersome or impossible in C alone.

The __asm keyword invokes the inline assembler and can appear wherever a C statement is legal. It cannot appear by itself. It must be followed by an assembly instruction, a group of instructions enclosed in braces, or, at the very least, an empty pair of braces. The term “__asm block” here refers to any instruction or group of instructions, whether or not in braces.

Below is a simple __asm block enclosed in braces. (The code prints the “beep” character, ASCII 7.)

__asm

{

mov ah, 2

mov dl, 7

int 21h

}

Alternatively, you can put __asm in front of each assembly instruction:

__asm mov ah, 2

__asm mov dl, 7

__asm int 21h

Since the __asm keyword is a statement separator, you can also put assembly instructions on the same line:

__asm mov ah, 2 __asm mov dl, 7 __asm int 21h

For more information, see Chapter 6 of the Programming Techniques manual.

Interrupt Functions (Microsoft Specific)

The __interrupt keyword specifies that the function is an interrupt handler. The compiler generates appropriate entry and exit sequences for the handling function, including saving and restoring all registers and executing an IRET instruction to return. Use this form to specify an interrupt function:

__interrupt declarator

where declarator is the name of the function to be called. An interrupt function must be __far. If you are compiling with the small (default) or compact memory model, you must explicitly declare the function with the __far attribute. An interrupt function cannot be declared as an inline function.

Interrupt functions must observe the C calling convention. If you use the /Gc compiler option (forcing the __pascal or __fortran calling convention) or the /Gr compiler option (forcing the __fastcall calling convention), you must explicitly declare your interrupt-handling function with the __cdecl attribute.

You cannot declare an interrupt function with both the __interrupt attribute and the __saveregs attribute or the __fastcall calling convention.

This example statement declares a function pointer that can be used to point to an interrupt handler:

void ( __interrupt __far *oldtime ) ( void );

The __interrupt keyword is implemented for 32-bit targets. See Help for more information on writing interrupt functions.

Using __loadds and __saveregs (Microsoft Specific)

The __loadds keyword causes the data-segment (DS) register to be loaded with a specified segment value upon entering the specified function. The previous DS value is restored when the function terminates. Use this form for __loadds:

__loadds declarator

The declarator specifies the function name of a function that must load DS as part of its entry sequence. Loading the DS register is essential for Windows callback functions and Windows entry points. The __loadds keyword does not imply any change in calling convention. It can be specified with any calling-convention modifier.

The compiler uses the segment name specified by the /ND (name-data-segment) option, or, if no segment has been specified, the default group, DGROUP. The __loadds attribute has the same effect as the /Au option, but on a function-by-function basis.

The __loadds keyword does not imply any change in the calling convention. It can be specified with any calling convention attribute that is supported for 16-bit targets.

The __saveregs keyword causes the compiler to generate code that saves all CPU registers when entering a function and also the code that restores the registers on exit. Note that __saveregs does not restore registers used for a return value (the AX register, or AX and DX). The form for using __saveregs is:

__saveregs declarator

The declarator specifies the function name whose entry sequence must save the values of all registers. The __saveregs keyword is useful when the register conventions of the caller are unknown. It is illegal to declare a function with both the __saveregs and __interrupt attributes.