Constants are values that do not change during the life of the program. Constants are like variables in that the name of the constant refers to the defined value, but unlike a variable, these values cannot be changed in the program. There are two important reasons why constants should be used in your program.
The first reason is that they help to document the program. Suppose in your role-playing game you have a weapon such as a broadsword. If you define the broadsword as a constant, which you can do with #Define broadsword 12, you can then refer to the weapon id as broadsword, rather than 12. The number 12 imparts no real information when you see it in the code; broadsword on the the other hand is quite clear and understandable.
The second reason to use a constant is code maintenance. There may come a time when working on your role-playing game that you need to change the value of the broadsword id. If you have defined the id as a constant, you only need to change it in a single location, the place where you defined the constant. If you had just used the number 12, you would have to search through the code and change each instance where 12 referred to the broadsword. If the program is of any length at all, you will probably miss a reference or two, introducing bugs into your program. Bugs that may be difficult to locate and fix.
One of the things you will discover as you progress in your programming adventure is that programs are dynamic, not static. There is always a new technique being developed that you can use, a new compiler function that will improve your program, and bugs that need to be fixed. The only thing that stays the same in a program is the fact that programs continually evolve over time. You should always keep in mind that when you write a program, you will probably end up making changes to the program, and you should code accordingly. It may be easier to write 12 than it is to write broadsword, but a few extra seconds of typing will save you hours when you need to change 12 to 120.
#Define as a Constant
#Define is a preprocessor command, where the defined symbol is physically replaced in the code by the associated value. #Define of course is used in a number of situations, from creating macros to conditional compilation, but it is also useful for creating constants within your program.
If you look through the declaration files in the include folder of your FreeBasic installation, you will see that #Define is used extensively for constant values. Since the compiler replaces the symbol definition with the defined value, it is a very efficient coding method. It is also quite easy to use, as the following code snippet illustrates.
'Define directions
#Define north 1
#Define neast 2
#Define east 3
#Define seast 4
#Define south 5
#Define west 6
#Define swest 7
#Define nwest 8
Once you define the constants, you can use the symbols in your programs just as you would the values.
If pdir = north Then
'do something
End If
The Const Keyword
The Const keyword is another method to define constants in your program. The format is similar to the #define, as the following code snippet illustrates.
Const xk = Chr(255)
Const key_up = xk & Chr(72)
Const key_dn = xk & Chr(80)
Const key_rt = xk & Chr(77)
Const key_lt = xk & Chr(75)
These constants are the character codes returned by Inkey for the arrow keys. Inkey returns a two byte string for the extended keys, Chr(255) + the extended key character code. To use these constaints in your program you would just use key_lt for example to check to see if the left arrow key had been pressed.
Const Versus #Define
As you can see Const and #Define are similar constructs. The question then becomes, which one should you use? Remember that #Define replaces the symbol name with the text following the symbol. If you wrote #Define key_up xk & Chr(72), then the code xk & Chr(72) would be replace the symbol key_up. If you had several places where you used key_up, then there would be several instances of xk & Chr(72) in your program. You can see that by using #Define in this case your program would be performing the same calculation over and over. It is much more efficient to use Const in this case, since the calculation is only done once, when the Const is defined.
On the other hand, if you are defining single constant values, such as compass directions, then using a #Define is preferable to using Const. For a Const value, the compiler must do a lookup in the symbol table and it is much more efficient to simple replace the symbol with the value using #Define.
Enumerations
Enumerations are sequential values that the compiler can calculate for you. To create an enumeration, you use enclose the values within an Enum-End Enum block. The compass direction defined above could also be defined as an enumeration.
Enum compass
north = 1
neast
east
seast
south
west
swest
nwest
End Enum
In this example, neast will be defined as 2, with east defined as 3 and so on. If no starting value is set, enumerations start at 0. You can also change the sequence within an enumeration by setting a symbol to a value using =, and any following symbols will be incremented from this starting point.
Enum compass
north = 1
east
south
west
neast = 10
seast
swest
nwest
End Enum
In this example, the value of seast will be 11, swest will be 12 and so on. Once you define an enumeration, you can create variables of the Enum and use that variable within your program.
Dim aCompass as compass
You can then use the enumeration values to initialize the variable. The following code snippet set aCompass to the north-defined value.
aCompass = north
The compiler does not check to see if the value being passed to the Enum variable is within the defined range of the enumeration. It is the responsibility of the programmer to ensure that the Enum variable contains the correct values.
The Preprocessor
FreeBasic has a preprocessor much like the C programming language. The preprocessor directives allow you to perform conditional compilations and to create macros within your program. The following table lists the preprocessor directives.
| Directive | Syntax | Comments |
|---|---|---|
| #define | #define symbol #define text #define macro() |
Defines a symbol, text or macro. |
| #else | #else | Used within an #if, #ifdef or #ifndef to provide alternate results. |
| #elseif | #elseif (expression) | Provides an additonal #if qualifier. |
| #endif | #endif | Closes an #if, #ifdef or #ifndef block. |
| #endmacro | #endmacro | Closes a macro block. |
| #error | #error error_text | Stops compilation and displays error text. |
| #if | #if (expression) | Conditionally includes statements within #if and #endif if expression is True. |
| #ifdef | #ifdef symbol | Conditionally includes statements within #ifdef and #endif if symbol exists. |
| #ifndef | #ifndef symbol | Conditionally includes statements within #ifdef and #endif if symbol does not exist. |
| #inclib | #inclib "filename" | Includes library file in the linking process. Library files are pre-compiled code modules ending with the .a extension. |
| #include | #include [once] "filename" | Includes inserts a source code module into the current source. The once identifier will prevent multiple files from being loaded. |
| #libpath | #libpath path | Adds a library search path to the linker search path. |
| #line | #line number ["name"] | Changes the line number and file name in the __FILE__ and __LINE__ macros. |
| #macro | #macro name[(parm1 [, parm2…])] | Starts a macro block which is ended with #endmacro. |
| #print text | Prints text during compilation. | |
| #undef | #undef symbol | Erases a symbol definiton previously created using #define. |
Conditional Compilation
Using the processor directives, you can create different versions of your program. You may want to have a debugging version and a release version and by using the listed directives, you can create code blocks that will only get compiled under certain situations. The following example demonstrates this concept.
#define debug
#ifdef debug
print "Variable value is ";myVar
#endif
Another example is in creating constants within your program.
#ifndef False
#define False 0
#define True (Not False)
#endif
Creating and Using Macros
A macro is a small piece of code that is defined in your program using either the #Define directive or by using the #Macro and #EndMacro directives. Macros are used to create inline code that can be executed without the overhead of a function call.
Like a function, a macro can take parameters and operate on the parameters returning a value. The parameters types are defined by the compiler based on the data type that is used when the macro is called. Often times you will need to be sure the passed parameters are of a certain type, so you should use the built-in conversion functions to cast the parameters to the needed type.
The following code snippet shows the definition of the RGB macro.
#define RGB(R,G,B) (((R)Shl 16) Or ((G)Shl 8) Or (B))
Once defined, you would call the macro just like a function.
myColor = RGB(255, 234, 200)
To create a multi-line macro you would use the #Macro and #EndMacro directives. The following macro definition swaps two values using the Xor operator.
#macro XSwap(a, b)
a = a Xor b
b = b Xor a
a = a Xor b
#endmacro
Once defined you would call this macro as:
XSwap(a, b)
Macros can be viewed as small programs, and as such you can Dim variables within a macro and use them in the code as the following example illustrates.
#macro TSwap(a, b)
Scope
Dim tmp As Integer
tmp = b
b = a
a = tmp
End Scope
#endmacro
Here the Scope and End Scope keywords are used to create a temporary scope block for the variable tmp. Using Scope-End Scope will prevent name clashes within your program and is recommended whenever you need to create variables within your macros.
Built-In Macros
FreeBasic has a number of built-in macros that you can use in your programs. These are help in a number of areas from version checking to debugging. The following lists all the macros currently available. All the macros have a double underscore before and after the macro name.
| Macro | Comment |
|---|---|
| __DATE__ | Returns the compiler data. |
| __FB_ARGC__ | Reurns the number of arguments passed on the command line. |
| __FB_ARGV__ | Returns a pointer to a list of pointers of Null terminated command line arguments. |
| __FB_BIGENDIAN__ | Used to set the compiler to big endian. |
| __FB_BUILD_DATE__ | Returns the the date of the compiler build. |
| __FB_DEBUG__ | Indicates whether the debug switch -g was used during the program compile. |
| __FB_ERR__ | Indicates whether error checking switches -e, -ex, -exx was used during program compile. |
| __FB_DOS__ | Indicates a program or section of code that should be compiled for DOS. |
| __FB_LANG__ | Indicates the language compatibility option set during program compile. |
| __FB_LINUX__ | Indicates a program or section of code that should be compiled for Linux. |
| __FB_MAIN__ | Defined in the main startup module. |
| __FB_MIN_VERSION__( major, minor, patch) | Returns 0 if the compiler version is less than the specified version, or -1 if the compiler version is greater than or equal to specified version. |
| __FB_MT__ | Indicates of the multi-threaded switch -mt was used during program compile. |
| __FB_OPTION_BYVAL__ | Returns -1 if parameters to subroutines or functions are passed by value, or 0 if by reference. |
| __FB_OPTION_DYNAMIC__ | Returns 0 if array allocation is set to dynamic, or -1 if set to static. |
| __FB_OPTION_ESCAPE__ | Returns -1 if string literals are processed for escape values when no prefixed with $ or !. |
| __FB_OPTION_EXPLICIT__ | Returns -1 if Option Explicit has been set in the source code, or 0 if not set. |
| __FB_OPTION_PRIVATE__ | Returns -1 if Option Private has been set in the source code, or 0 if not set. |
| __FB_OUT_DLL__ | Returns -1 if the program has been compiled as a shared library (DLL). |
| __FB_OUT_EXE__ | Returns -1 if the program has been compiled as an EXE. |
| __FB_OUT_LIB__ | Returns -1 if the program has been compiled as a library (.a). |
| __FB_OUT_OBJ__ | Returns -1 if the program has been compiled as an object file (.o). |
| __FB_SIGNATURE__ | Returns the signature of the compiler; i.e. FreeBASIC v0.17b. |
| __FB_VER_MAJOR__ | Returns the major version of the compiler. |
| __FB_VER_MINOR__ | Returns the minor version of the compiler. |
| __FB_VER_PATCH__ | Returns the patch version of the compiler. |
| __FB_VERSION__ | Returns the version number of the compiler. |
| __FB_WIN32__ | Indicates a program or section of code that should be compiled for Windows. |
| __FILE__ | Returns the quoted source file name. |
| __FILE_NQ__ | Returns the non-quoted source file name. |
| __FUNCTION__ | Returns the quoted name of the current function block. |
| __FUNCTION_NQ__ | Returns the non-quoted name of the current function block. |
| __LINE__ | Returns the current line number. |
| __PATH__ | Returns the absolute, quoted source file path. |
| __TIME__ | Returns the time the compiler was compiled in 24-hour format. |
As you can see there are numerous macros that you can use to gain information on just about every aspect of the compiler and the compiled source code.





