xHarbour Reference Documentation > Preprocessor Reference |
Defines a symbolic constant or pseudo-function.
#define <Constant> [<value>] #define <Function>([<params,...>]) [<expr>]
One of the most important directives is the #define directive. It is used to define a symbolic name and optionally associate it with a constant value, or to define a pseudo-function. Both, #define constants and pseudo-functions, help a programmer to maintain PRG source code better, and enhance its readability. In addition, #define constants are used for the purpose of conditional compilation in conjunction with the #if, #ifdef and #ifndef directives.
The #define directive is processed by the preprocessor, similar as #command and #translate. The major difference, however, is that #define directives are case sensitive and are coded without the => characters as separators.
Symbolic constants
A common usage for the #define directive is the definition of symbolic constants that are optionally associated with a constant value. By convention, the names of symbolic constants are coded in upper case so they are easily recognized in the PRG source code. When a symbolic constant is associated with a value, the symbolic name of the constant value can be used similar as the usage of a named memory variable. The difference is, that the value of a symbolic constant cannot change at runtime of a program. This is because symbolic constants are resolved by the preprocessor, while memory variables are run-time entities.
The following code example explains the difference between a symbolic constant and a memory variable:
// PRG code #define K_INS 22 #define _SET_INSERT 29 nKey := Inkey(0) IF nKey == K_INS Set( _SET_INSERT, .NOT. Set( _SET_INSERT ) ) ENDIF
This code queries a key press using the Inkey() function. When the user presses the Ins key, the setting for insert/overwrite mode is toggled. The code relies on two symbolic constants, K_ESC and _SET_INSERT, and both have a numeric value associated. This allows a programmer to use a symbolic name for the IF condition and the Set() function call.
The code is processed by the preprocessor. As a result, the compiler processes the following:
// PPO code nKey := Inkey(0) IF nKey == 22 Set(29, .NOT. Set(29 ) ) ENDIF
A programmer could have coded the preprocessor result in the first place. It is, however, more intuitive for a programmer to use symbolic names in PRG code than to memorize numeric constants for a variety of reasons. It becomes also clear that while nKey, as a memory variable, can change its value later in the program, symbolic #define constants cannot: they are replaced with their associated constant value at compile time.
Pseudo-functions
A #define directive can be coded in functional syntax. Function calls that match with such an directive are translated by the preprocessor and replaced with the result pattern of the directive. The following example illustrates this:
// PRG code #define InRange( val, low, high ) (val >= low .AND. high >= val) n := 10 nLow := 5 nHigh := 11 IF InRange( n, nLow, nHigh ) ? "value fits in range" ENDIF
The IF condition looks syntactically like a function call accepting three memory variables as arguments. However, there is no function call due to the #define directive. The compiler processes an .AND. expression instead:
// PPO code n := 10 nLow := 5 nHigh := 11 IF (n >= nLow .AND. nHigh >= n) QOut("value fits in range" ) ENDIF
The usage of pseudo-functions is advantageous when a function call can be coded as a complex one-line expression. This can relieve a programmer from much typing and reduces the size of the resulting executable file since the overhead of a function call can be avoided. Note, however, that the name of the pseudo-function is case-sensitive, and that the function must be coded with the exact number of arguments specified in the #define directive.
Conditional compilation
A third area where #define directives play an important role is conditional compilation. Program code can be compiled in different ways depending on the presence or absence of #define constants and/or their values. This is accomplished in conjunction with the directives #if, #ifdef and #ifndef. Please refer to these topics for examples of Conditional compilation.
See also: | #command | #translate, #if, #ifdef, #ifndef, #undef, #xcommand | #xtranslate |
Category: | Preprocessor directives |
http://www.xHarbour.com