This section summarizes the details unique to the C and MASM interface. The information is accurate for Microsoft C 6.0 and QuickC version 2.5.
With the default naming and calling convention, the assembler (or compiler) pushes arguments right to left and adds a leading underscore to routine names.
This list shows the C data types that are equivalent to the MASM 6.0 data types.
C Type | Equivalent MASM Type | |
unsigned char | BYTE | |
char | SBYTE | |
unsigned short, unsigned int | WORD | |
int, short | SWORD | |
unsigned long | DWORD | |
float | REAL4 | |
C Type | Equivalent MASM Type | |
long | SDWORD | |
double | REAL8 | |
long double | REAL10 |
C is case sensitive and does not convert names to uppercase. Since C normally links with the /NOI command-line option, assemble MASM modules with the /Cx or /Cp option to prevent the assembler from converting names to uppercase.
When the C module is compiled in small or medium model and when a distance is not specified, the C compiler passes arrays by near reference. In compact, large, or huge model, C arrays are passed by far reference (if a distance is not explicitly specified). All other types defined in the C module are passed by value. You can pass by reference if you specifically pass pointers or addresses.
Changing the Calling Convention
Put _pascal or _fortran in the C function declaration to specify the Pascal calling convention.
Array declarations give the number of elements. A1[a][b] declares a two-dimensional array in C with a rows and b columns. By default, the array's lower bound is zero. Arrays are stored by the compiler in row-major order. By default, passing arrays from C passes a pointer to the first element of the array.
C stores strings as arrays of bytes and uses a null character as the end-of-string delimiter. For example, consider the string declared as follows:
char msg[] = "string of text"
The string occupies 15 bytes of memory as:
Since msg is an array of characters, it is passed by reference. To pass by value, declare the string to be a member of a structure and pass the structure.
Summary: External data can be accessed directly by other modules.
In C, the extern keyword tells the compiler that the data or function is external. You can define a static data object in a C module by defining a data object outside all functions and subroutines. Do not use the static keyword in C with a data object that you wish to be public.
Summary: C structures are word-aligned by default.
By default, C uses word alignment (unpacked storage) for all data objects longer than one byte. This storage method specifies that occasional bytes may be added as padding, so that word and doubleword objects start on an even boundary. In addition, all nested structures and records start on a word boundary. MASM is byte-aligned by default.
When transferring .H files with H2INC, you can use the /Zp command-line option to specify structure alignment. If the /Zp option is not specified, H2INC uses word-alignment. Without H2INC, set the alignment to 2 when declaring the MASM structure, or compile the C module with /Zp1 or the MASM module with /Zp2.
Use the same memory model for both C and MASM.
The assembler returns simple data types in registers. Table 20.2 shows the register conventions for returning simple data types to a C program.
Table 20.2 Register Conventions for Simple Return Values
Data Type | Registers, | ||
char | AL, | ||
int, short, near | AX, | ||
long, far | High-order portion (or segment address) in DX; low-order portion (or offset address) in AX, | ||
^ |
Procedures using the C calling convention and returning type float or type double store their return values into static variables. In multi-threaded programs, this could mean that the return value may be overwritten. You can avoid this by using the Pascal calling convention for multi-threaded programs so float or double values are passed on the stack.
Summary: Your procedures can also return structures.
Structures less than four bytes long are returned in DX:AX. To return a longer structure from a procedure that uses the C calling convention, you must copy the structure to a global variable and then return a pointer to that variable in the AX register (DX:AX, if you compiled in compact, large, or huge model or if the variable is declared as a far pointer).
Structures, Records, and User-Defined Data Types
You can pass structures, records, and user-defined types as arguments by value or by reference.
The H2INC utility simplifies the task of writing prototypes for the C functions you want to call from MASM. The C prototype converted by H2INC into a MASM prototype allows INVOKE to correctly call the C function. Here are some examples of C functions and the MASM prototypes created with H2INC.
/* Function Prototype Declarations to Convert with H2INC */
long checktypes (
char *name,
unsigned char a,
int b,
float d,
unsigned int *num );
my_func (float fNum, unsigned int x);
extern my_func1 (char *argv[]);
struct videoconfig _far * _far pascal my_func2 (int, scri );
For the C prototypes above, H2INC generates this code:
TYPEDEF PROTO C :PTR SBYTE, :BYTE,
:SWORD, :REAL4, :PTR WORD
checktypes PROTO @proto_0
@proto_1 TYPEDEF PROTO C :REAL4, :WORD
my_func PROTO @proto_1
@proto_2 TYPEDEF PROTO C :PTR PTR SBYTE
my_func1 PROTO @proto_2
@proto_3 TYPEDEF PROTO FAR PASCAL :SWORD, :scri
my_func2 PROTO @proto_3
As shown in the short example below, the main module (written in C) calls an assembly routine, Power2.
#include <stdio.h>
extern int Power2( int factor, int power );
void main()
{
printf( "3 times 2 to the power of 5 is %d\n", Power2( 3, 5 ) );
}
Figure 20.2 shows how functions that observe the C calling convention use the stack frame.
The MASM module that contains the Power2 routine looks like this:
.MODEL small, c
Power2 PROTO C factor:SWORD, power:SWORD
.CODE
Power2 PROC C factor:SWORD, power:SWORD
mov ax, factor ; Load Arg1 into AX
mov cx, power ; Load Arg2 into CX
shl ax, cl ; AX = AX * (2 to power of CX)
; Leave return value in AX
ret
Power2 ENDP
END
The MASM procedure declaration for the Power2 routine specifies the C langtype and the parameters expected by the procedure. The langtype specifies the calling and naming conventions for the interface between MASM and C. The routine is public by default. When the C module calls Power2, it passes two arguments, 3 and 5 by value.
The C module first defines a prototype for the MASM routine. MASM 6.0 also supports prototyping of procedures and functions. See Section 7.3.6, “Declaring Procedure Prototypes,” and the examples in this section.