Functions and Directives

Directive #define Foundation

Defines symbolic constants or pseudofunctions

Syntax
#define <Constant>  [<ResultCode>]
#define <FuncName>( [<Arguments,...>] )  [<Expression>]
Parameters
<Constant>
<Constant> designates the name for a symbolic constant.
<ResultCode>
<ResultCode> defines the characters with which the preprocessor replaces those characters matching what is contained in <Constant>. <ResultCode> is optional.
<FuncName>
<FuncName> designates the name of a pseudofunction, with which an optional argument list <Arguments,...> may be used. The argument list must be enclosed in parentheses and individual arguments should not be enclosed in angle brackets.
<Expression>
<Expression> defines the expression which the preprocessor outputs to the intermediary file. The expression should always be enclosed in parentheses to avoid compilation errors.
Note: Unlike the #translate or #command directives, #define differentiates between upper and lower case.
Description

The #define directive is used to define symbolic constants or pseudofunctions. #define causes the preprocessor to perform a strict search and replace. The preprocessor uses <Constant> or <FuncName> as the search pattern, and replaces every instance that it finds with those characters identified in the [<ResultCode>] or [<Expression>] portion. As with all Directives, the intermediary file created by the preprocessor can be saved for review after the compile by using the /P compiler switch.

Constants or pseudofunctions follow the same naming convention as variable or function names. They must begin with a letter or an underscore (_), and consist entirely of alphanumeric characters. Note that because #define differentiates between upper and lower case when performing a match, it is generally advisable to use #translate or #xtranslate for defining pseudofunctions.

It is considered standard practice to write #define constants or pseudofunctions in capital letters in source code so that they can be easily differentiated from other code. Furthermore, a convention used by many programmers is to create #define constants with a known prefix, by which they can be grouped and easily understood.

When constructing a #define, there should be one or more blank spaces between the #define and the <Constant> or <FuncName> portions of the directive. If a <ResultCode> is defined, this must also be separated from the other portions of the directive by one or more spaces. The symbol => used with the #command and #translate directives is not used with #define. Each #define must be coded as a single statement. If a particular #define requires several lines, a semicolon must be used at the end of the line as a line continuation character.

A #define directive is recognized by the preprocessor from the point it is defined until the end of that program file. Preprocessor directives can also be stored in Include files and are recognized by the preprocessor from the line in which they are referenced with the #include directive, until the end of the program file. Since STD.CH is the source of an implicit #include in every program file, any additions to this header file are automatically recognized in every program. In addition, the command line compiler switch /U allows the programmer to specify a replacement for STD.ch, so that any directives included in the replacement header file will also be recognized in any program they are used. Contrary to the #command and #translate directives, #define directives can be undefined using #undef, then defined differently at a subsequent point in code.

The directive #define is used for three purposes:

The definition of symbolic constants that are the subject of #ifdefand #ifndef directives for conditional compilation.

The definition of readily understandable symbolic constants which are replaced with less readable values prior to compilation.

The definition of pseudofunctions.

Preprocessor constants

A preprocessor constant is defined by #define <Constant> without any replacement value. The existence of such a constant can be tested by the directives #ifdef or #ifndef. This provides the ability to conditionally compile blocks of code, depending on the presence or absence of a particular preprocessor constant. For example, a typical constant is #define DEBUG. Combining this constant with blocks of code within #ifdef DEBUG ... #endif directives ensures that code will be compiled that provide extra information to track errors. When debugging is complete, the #define DEBUGdirective can be removed. Subsequent compiles will not include the code between the #ifdef DEBUG and #endif directives. A preprocessor constant can also be defined on the compiler command line by using the /D compiler switch.

Symbolic constants

Symbolic constants are defined by a #define directive that includes a result code <ResultCode> value following the <Constant>symbol. This constant is the most common use of #define, and in practice serves as a strict search and replace mechanism. A typical example of such a directive is the definition of a symbol for an Inkey() code or for a character string used with the @...BOX command. Here are some examples:

#define  K_RETURN  13 
#define  B_SINGLE  Chr(218) + Chr(196) + Chr(191) + Chr(179) + ; 
                   Chr(217) + Chr(196) + Chr(192) + Chr(179) 

IF LastKey() == K_RETURN 
   @ 10, 10, 20, 50  BOX  B_SINGLE 
ENDIF 

When using symbolic constants, the preprocessor replaces all constants it finds in the source code with their associated value. This approach has the advantages of making source code more readable, and reducing runtime overhead. Code is more readable because the constant can be much more intuitive than the associated value. Runtime overhead can be reduced and execution increased because constants can remove the necessity for using variables. In addition, since preprocessor directives can be grouped into an Include file, changing the value of a constant across the various source code files that reference the Include file is a matter of changing the value associated with the constant in the appropriate Include file and performing a recompile of the source code modules involved (see #include).

Pseudofunctions

A pseudofunction is an expression that follows a similar syntax for calling a function. It consists of the function name followed by a list of arguments enclosed in parentheses. Contrary to an actual function, a pseudofunction does not have a function body. Instead, it has an associated expression that is written to the intermediary file in its place that is the subject of the compile.

The following example shows how to use #define to create a pseudofunction:

#define  MinMax( x, min, max )     (x >= min .AND. max >= x) 

This type of #define differs from the symbolic constant type by virtue of the argument list. Instead of doing straight translation, the preprocessor detects which values in the source code correspond to the individual arguments listed in the search pattern, and writes those values to the intermediary file in the location specified by the arguments in the output expression.

The output of the example #define pseudofunction MinMax() is demonstrated in the following example:

// Code in the source file  (PRG file) 
   IF MinMax( 5, 1, 10 ) 

// Code for the compiler 
   IF (5 >= 1 .AND. 10 >= 5) 

Pseudofunctions make programming easier since less code must be written to achieve the desired result. The preprocessor outputs the valid, compilable source that in many cases, such as in the above example, eliminates the overhead of a function call. The disadvantage of pseudofunctions is that each instance of the pseudofunction represents insertion of the same translated source code text. If the translated code is very large or occurs in many places, this can lead to code bloat within the executable (EXE) file. It is important therefore to weigh the benefits of inserting code to reduce function call overhead with increasing overall code size.

Note that because the #define directive is used to create pseudofunctions, the preprocessor differentiates between upper and lower case when identifying text to translate. This means that in order for the translation to work, the pseudofunction must be typed exactly as it appears in the directive. Furthermore, all arguments listed in the directive must be present in the source code for a match to occur. When an argument is missing or if case does not match, the preprocessor ignores the source code. To support optional arguments or case insensitivity, use the #translate or the #xtranslate directive instead of #define see #command/#translate).

Examples
#define samples

// This example uses #define constants for indexing into 
// array elements 

#define  DBS_NAME      1            // Field name 
#define  DBS_TYPE      2            // Field type 
#define  DBS_LEN       3            // Field length 
#define  DBS_DEC       4            // Placing of decimal 

PROCEDURE Main 
   LOCAL aStructure, I, nLen 

   USE Customer 

   aStructure := DbStruct()         // Create an array of 
   nLen       := Len(aStructure)    // .dbf structure 

   FOR i:=1 TO nLen 
      ? aStructure[i, DBS_NAME], ;  // Display the structure 
        aStructure[i, DBS_TYPE], ; 
        aStructure[i, DBS_LEN] , ; 
        aStructure[i, DBS_DEC] 
   NEXT 

   CLOSE Customer 
RETURN 
Feedback

If you see anything in the documentation that is not correct, does not match your experience with the particular feature or requires further clarification, please use this form to report a documentation issue.