Chapter Eight (Part 5)
|Table of Content||
Chapter Eight (Part 7)
MASM: DIRECTIVES & PSEUDO-OPCODES (Part 6)
8.13.1 - IF Directive
8.13.2 - IFE directive
IFDEF and IFNDEF
8.13.4 - IFB IFNB
8.13.5 - IFIDN IFDIF IFIDNI and IFDIFI
|8.13 Conditional Assembly|
MASM provides a very powerful conditional assembly facility. With conditional assembly you can decide based on certain conditions whether MASM will assemble the code. There are several conditional assembly directives the following section covers most of them.
It is important that you realize that these directives
evaluate their expressions at assembly time
not at run time. The
assembly directive is not the same as a Pascal or C "if" statement. If you are
familiar with C
#ifdef directive in C is roughly equivalent to some of
MASM's conditional assembly directives.
MASM's conditional assembly directives are important because they let you generate different object code for different operating environments and different situations. For example suppose you want to write a program that will run on all machines but you would like to optimize the code for 80386 and later processors. Obviously you cannot execute 80386 code on an 8086 processor so how can you solve this problem?
One possible solution is to determine the processor type at run time and execute different sections of code in the program depending on the presence or absence of a 386 or later CPU. The problem with this approach is that your program needs to contain two code sequences - an optimal 80386 sequence and a compatible 8086 sequence. On any given system the CPU will only execute one of these code sequences in the program so the other sequence will be wasting memory and may have adverse affects on any cache in the system.
A second possibility is to write two versions of the code one that uses only 8086 instructions and one that uses the full 80386 instruction set. During installation the user (or the installation program) selects the 80386 version if they have an 80386 or later processor. Otherwise they select the 8086 version. While this marginally increases the cost of the software since it will require more disk space the program will consume less memory while running. The problem with this approach is that you will need to maintain two separate versions of the program. If you correct a bug in the 8086 version of the code you will probably need to correct that same bug in the 80386 program. Maintaining multiple source files is a difficult task.
A third solution is to use conditional assembly. With conditional assembly you can merge the 8086 and 80386 versions of the code into the same source file. During assembly you can conditionally choose whether MASM assembles the 8086 or the 80386 version. By assembling the code twice you can produce an 8086 and an 80386 version of the code. Since both versions of the code appear in the same source file the program will be much easier to maintain since you will not have to correct the same bug in two separate source files. You may need to correct the same bug twice in two separate code sequences in the program but generally the bug will appear in two adjacent code sequences so it is less likely that you will forget to make the change in both places.
MASM's conditional assembly directives are especially useful within macros. They can help you produce efficient code when a macro would normally produce sub-optimal code. For more information about macros and how you can use conditional assembly within a macro see "Macros".
Macros and conditional assembly actually provide "a programming language within a programming language." Macros and conditional assembly let you write programs (in the "macro language") that write segments of assembly language code for you. This introduces an independent way to generate bugs in your application programs. Not only can a bug develop in your assembly language code you can also introduce bugs in your macro code (e.g. conditional assembly) that wind up producing bugs in your assembly language code. Keep in mind that if you get too sophisticated when using conditional assembly you can produce programs that are very difficult to read understand and debug.
8.13.1 IF Directive
if directive uses the following syntax:
if expression <sequence of statements> else ;This is optional! <sequence of statements> endif
MASM evaluates expression. If it is a non-zero value
MASM will assemble the statements between the
else isn't present). If the expression
evaluates to zero (false) and an
else section is present
MASM will assemble
the statements between the
else directive and the
else section is not present and expression evaluates to false
MASM will not assemble any of the code between the
The important thing to remember is that expression has to
be an expression that MASM can evaluate at assembly time. That is
it must evaluate to a
constant. Manifest constants (equates) and values that MASM's type operators produce are
commonly found in
if directive expressions. For example
suppose you want to
assemble code for two different processors as described above. You could use statements
like the following:
Processor = 80386 ;Set to 8086 for 8086-only code . . . if Processor eq 80386 shl ax 4 else ;Must be 8086 processor. mov cl 4 shl ax cl endif
There are other ways to accomplish this same thing. MASM provides built-in variables that tell you if you are assembling code for some specific processor. More on that later.
8.13.2 IFE directive
ife directive is used exactly like the
except it assembles the code after the
ife directive only
if the expression evaluates to zero (false)
rather than true (non-zero).
8.13.3 IFDEF and IFNDEF
These two directives require a single symbol as the
Ifdef will assemble the associated code if the symbol is defined
will assemble the associated code if the symbol isn't defined. Use
endif to terminate the conditional assembly sequences.
These directives are especially popular for including or not including code in an assembly language program to handle certain special cases. For example you could use statements like the following to include debugging statements in your code:
ifdef DEBUG <place debugging statements here> endif
To activate the debugging code
simply define the symbol
somewhere at the beginning of your program (before the first
DEBUG). To automatically eliminate the debugging code
simply delete the
DEBUG. You may define
DEBUG using a simple
DEBUG = 0
Note that the value you assign to
unimportant. Only the fact that you have defined (or have not defined) this symbol is
8.13.4 IFB IFNB
useful mainly in macros (see
"Macros") check to see if an operand is blank (
ifb) or not blank (
Consider the following code:
Blank textequ <> NotBlank textequ <not blank> ifb Blank <this code will assemble> endif ifb NotBlank <this code will not> endif
ifnb works in an opposite manner to
it would assemble the statements above that
ifb does not and vice
8.13.5 IFIDN IFDIF IFIDNI and IFDIFI
These conditional assembly directives take two operands and
process the associated code if the operands are identical (
identical ignoring case (
or different ignoring
ifdifi). The syntax is
ifidn op1 op2 <statements to assemble if <op1> == <op2>> endif ifdif op1 op2 <statements to assemble if <op1> != <op2>> endif ifidni op1 op2 <statements to assemble if <op1> == <op2>> endif ifdifi op1 op2 <statements to assemble if <op1> != <op2>> endif
The difference between the
statements above is that the
IFxxxI statements ignore differences in
alphabetic case when comparing operands.
Chapter Eight: MASM: Directives &
Pseudo-Opcodes (Part 6)
26 SEP 1996