It is sometimes useful to make procedures and variables (such as large arrays or status flags) global to all program modules. Global variables are freely accessible within all routines; you do not have to explicitly pass them to the routines that need them.
Variables can be made global to multiple modules in several ways. This section describes three ways to make them global by using the EXTERNDEF, PROTO, or COMM declarations within include files. Section 8.3.1 explains how to use the PUBLIC and EXTERN directives within modules.
Summary: External identifiers must be unique.
These methods make symbols global to the modules in which they are used. Therefore, symbols must be unique. The linker enforces this requirement.
Summary: EXTERNDEF can appear in the defining or calling modules.
MASM treats EXTERNDEF as a public declaration in the defining module and as an external declaration in accessing module(s). You can use the EXTERNDEF statement in your include file to make a variable common among two or more modules. EXTERNDEF works with all types of variables, including arrays, structures, unions, and records. It also works with procedures.
As a result, a single include file can contain an EXTERNDEF declaration that works in both the defining module and any accessing module. It is ignored in modules that neither define nor access the variable. Therefore, an include file for a library which is used in multiple .EXE files does not force the definition of a symbol as EXTERN does.
The EXTERNDEF statement takes this form:
EXTERNDEF [[langtype]]name:qualifiedtype
The name is the variable's identifier. The qualifiedtype is explained in detail in Section 1.2.6, “Data Types.”
The optional langtype specifier sets the naming conventions for the name it precedes. It overrides any language specified in the .MODEL directive. The specifier can be C, SYSCALL, STDCALL, PASCAL, FORTRAN, or BASIC. See Section 20.1, “Naming and Calling Conventions,” for information on selecting the appropriate langtype type.
The diagram below shows the statements that declare an array, make it public, and use it in another module.
The file position of EXTERNDEF directives is important. See Section 8.2.3, “Positioning External Declarations,” for more information.
Summary: The assembler does not check parameters when you call EXTERNDEF procedures.
You can also make procedures visible by using EXTERNDEF without PROTO inside an include file. This method treats the procedure name as a simple identifier, without the parameter list, so you forgo the assembler's ability to check for the correct parameters during assembly.
The method for using EXTERNDEF for procedures is the same as using it with variables. You can also use EXTERNDEF to make code labels global.
When a procedure is defined in one module and called from another module, it must be declared public in the defining module and external in the calling modules; otherwise, assembly or linking errors occur.
You have three methods for declaring a procedure public. Using PUBLIC and EXTERN is the only method prior to MASM 6.0. Section 8.3.1 explains the use of PUBLIC and EXTERN. The previous section (8.2.2.1) explains the use of EXTERNDEF. This section illustrates the use of PROTO.
A PROTO (prototype) declaration in the include file establishes a procedure's interface in both the defining and calling modules. The PROTO directive automatically generates an EXTERNDEF for the procedure unless the procedure has been declared PRIVATE in the PROC statement. Defining a prototype enables type-checking for the procedure arguments.
Summary: PROTO and INVOKE simplify procedure calls.
Follow these steps to create an interface for a procedure defined in one module and called from other modules:
1.Place the PROTO declaration in the include file.
2.Define the procedure with PROC. The PROC directive declares the procedure PUBLIC by default.
3.Call the procedure with the INVOKE statement (or with CALL).
The following example is a PROTO declaration for the far procedure CopyFile, which uses the C parameter-passing and naming conventions, and takes the arguments filename and numberlines. The diagram following the example shows the file placement for these statements. This definition goes into the include file:
CopyFile PROTO FAR C filename:BYTE, numberlines:WORD
The procedure definition for CopyFile is
CopyFile PROC FAR C USES cx, filename:BYTE, numberlines:WORD
To call the CopyFile procedure, you can use this INVOKE statement:
INVOKE CopyFile, NameVar, 200
See Chapter 7, “Controlling Program Flow,” for descriptions, syntax, and examples of PROTO, PROC, and INVOKE.
Another way to share variables among modules is to add the COMM (communal) declaration to your include file. Since communal variables are allocated by the linker and cannot be initialized, you cannot depend on their location or sequence.
Communal variables are supported by MASM primarily for compatibility with communal variables in Microsoft C. Communal variables are not used in any other Microsoft language, and they are not compatible with C++ and some other languages.
Summary: Communal variables can reduce the size of executable files.
COMM declares a variable external but cannot be used with code. COMM also instructs the linker to define the variable if it has not been explicitly defined in a module. The memory space for communal variables may not be assigned until load time, so using communal variables may reduce the size of your executable file.
The COMM declaration has the syntax
COMM [[langtype]] [[NEAR| FAR]]label:type[[:count]]
The label is the name of the variable. The langtype sets the naming conventions for the name it precedes. It overrides any language specified in the .MODEL directive.
If NEAR or FAR is not specified, the variable determines the default from the current memory model (NEAR for TINY, SMALL, COMPACT, and FLAT; FAR for MEDIUM, LARGE, and HUGE).
The type can be a constant expression, but it is usually a type such as BYTE, WORD, or DWORD, or a structure, union, or record. If you first declare the type with TYPEDEF, CodeView can provide type information. The count is the number of elements. If no count is given, one element is assumed.
The following example creates the common far variable DataBlock, which is a 1,024-element array of uninitialized signed doublewords:
COMM FAR DataBlock:SDWORD:1024
NOTE:
C variables declared outside functions (except static variables) are communal unless explicitly initialized; they are the same as assembly-language communal variables. If you are writing assembly-language modules for C, you can declare the same communal variables in both C and MASM include files. However, communal variables in C do not have to be declared communal in assembler. The linker will match the EXTERN, PUBLIC, and COMM statements for the variable.
Summary: EXTERNDEF is a flexible alternative to using COMM.
EXTERNDEF (explained in the previous section) is more flexible than COMM because you can initialize variables defined with it, and you can use those variables in code that depends on the position and sequence of the data.