Preprocessor. General information. Preprocessor directives. Review.
Directives #define, #error, #include, #undef, #import, #using, #pragma, #line
Contents
- 1. Preprocessor. Purpose. Directives
- 2. Directive #define. Macro name definition
- 3. Directive #error. Display the error message
- 4. Directive #include. Including a header or other source file
- 5. The #undef directive
- 6. Directive #import. Including information from the type library
- 7. Directive #using. Including *.dll, *.obj, *.exe, *.net module files
- 8. Directive #pragma. Specifying execution functions for the compiler
- 9. Directive #line. Set string to file name in error messages
- Related topics
1. Preprocessor. Purpose. Directives
In the C++ programming language, the preprocessor is the part of the compiler that controls the formation of source code into object code. The C++ preprocessor is inherited from the C programming language. The preprocessor has a set of commands called preprocessor directives. With these directives, the preprocessor controls changes in the translation of source code into object code.
Any preprocessor directive begins with the # character. In C++, the preprocessor contains the following directives:
- #define
- #if
- #endif
- #undef
- #error
- #else
- #ifdef
- #line
- #include
- #elif
- #ifndef
- #pragma
- #using
- #line
- # or NULL.
⇑
2. Directive #define. Macro name definition
The #define directive defines an identifier and a sequence of characters that will replace this identifier in the program. More details about the #define directive and examples of its use can be found here.
The general usage of the directive is as follows
#define macro_name character_sequence
here
- macro_name – name that will be used in the program text;
- character_sequence – a sequence of characters that will replace the macro_name name every time it occurs in the program.
Example.
#include <iostream> using namespace std; // Raise x to the power of 4 #define ABC(x) x*x*x*x // Calculate the length of a line given two points #define LENGTH_LINE(x1, y1, x2, y2) std::sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2)) void main() { // 1. Use ABC macro int t = 3; int x = ABC(t); // x = 81 cout << "x = " << x << endl; // 2. Use LENGTH_LINE macro double x1, y1, x2, y2; x1 = 3.8; y1 = 2.7; x2 = -1.4; y2 = 5.5; double len = LENGTH_LINE(x1, y1, x2, y2); cout << "len = " << len << endl; }
⇑
3. Directive #error. Display the error message
Using the #error directive causes the compiler to pause compilation. This directive is used to debug a program.
The general form of using the #error directive is
#error error_message
where
- error_message – error message text.
Example.
In the example, the program will be compiled until the #error directive is encountered. Further, the compilation of the program will stop and an error message will be displayed.
#error: Compilation error
Thus, the *.exe file will not be created.
#include <iostream> using namespace std; void main() { // Calculations double a = 3, b = 10, c; c = a * b + 5; // Display the error message #error Compilation error. }
⇑
4. Directive #include. Including a header or other source file
Using the #include directive, you can include other external files in the source code of the current file. The text of these external files will be used when generating the executable module of the source file.
In turn, included files can also contain #include directives in their code. These directives are called nested. The C++ language standard allows up to 256 levels of nesting.
In the most general case, including a file named filename.h can be done in one of two ways:
#include "filename.h"
or
#include <filename.h>
The presence of quotation marks “” or angle delimiters <> determines how the file is searched to include. The first method (“filename.h”) searches for a file in the directory with the current program (working directory). If the file is not found, the second way to find the file is used (using <> delimiters).
The second method (<> delimiter) searches for the file in the directory specified by the compiler. Typically, this is a directory with all the header files called INCLUDE.
When including files, proprietary library files are included in double quotes “”, and standard library files are included in <> delimiters.
When designing a single-file program, it is good practice to split the program code into two files:
- file with *.h extension. This contains declarations (declarations only) of functions that are shared (available to the client);
- file with *.cpp extension. It contains implementations of all developed functions. This may include not only the functions that are shared, but also any other additional internal functions of the project.
Example.
// Inclusion of standard libraries time.h, iostream #include <time.h> #include <iostream> // Connecting a namespace using namespace std; // Including a user file my_file.h #include "my_file.h" void main() { }
⇑
5. The #undef directive
The #undef directive is used to remove the macro name defined by the #define directive. After using the directive, the name of the macro to be removed becomes undefined.
The general form of the #undef directive is as follows
#undef macros_name
where
- macros_name – macro name to be deleted.
Example.
#include <iostream> using namespace std; // Directive #undef // A macro that multiplies two numbers with each other #define Mult2(x, y) (x * y) // A macro that adds two numbers #define Add2(x, y) (x + y) void main() { // Checking if the name Mult2 exists #ifdef Mult2 double res = Mult2(2.5, 7.8); cout << "2.5 * 7.8 = " << res << endl; #endif // Undo name Add2 - #undef directive #undef Add2 // Checking if the name Add2 exists #ifdef Add2 int a = 8, b = 9; int resAdd = Add2(a, b); cout << "a + b = " << resAdd << endl; #else cout << "The Add2 name is undefined." << endl; #endif }
Result
2.5 * 7.8 = 19.5 The Add2 name is undefined.
⇑
6. Directive #import. Including information from the type library
Using the #import directive, you can include information from the type library (TLB – type library). In this context, a type library is a hierarchical repository of information about the Active-X server’s capabilities, which is stored as a *.tlb or *.olb file.
The general form of the declaration of the #import directive can be as follows
#import "filename" [attributes] #import <filename> [attributes]
where
- filename – the name of the file containing the type library. It can be a *.tlb, *.olb, *.dll or *.exe file. It can also be any other file format understood by the LoadTypeLib() API function;
- attributes – attributes of the directive. These attributes indicate that the compiler is modifying the content of the type library header. For more information about #import attributes, see the documentation at learn.microsoft.com.
Example.
#import "MyTypeLib"
⇑
7. Directive #using. Including *.dll, *.obj, *.exe, *.net module files
The #using directive imports metadata into a program that was compiled with the /clr option. This means that the directive can only be used in C++/CLI mode.
The general form of using the #using directive is as follows
#using filename [as_friend]
where
- filename – file name with extension *.dll, *.exe, *.net module or *.obj.
For example, to include a dynamic library named “MyLibrary.dll” you need to execute the following code
#using <MyLibrary.dll>
⇑
8. Directive #pragma. Specifying execution functions for the compiler
The #pragma directive allows you to specify functions to be executed by the compiler. The use of certain functions depends on the operating system and the current computer, which is called the host computer. The characteristics of the compiler functions are determined when you install the C/C++ compiler on your computer. Using the #pragma directive, you can offer the compiler various functions for processing them, ensuring full compatibility with C or C++ languages.
The #pragma directive has many uses and several implementations. The general form of one of the common implementations is as follows
#pragma token_string
where
- token_string – the so-called token string, which can have different values. This string is a set of characters that define a set of instructions and their arguments. Tokens include, for example, once, alloc_text, component, auto_inline, endregion, loop, etc.
A detailed consideration of the implementation features of the directive in combination with one or another token is not the subject of this topic.
Example.
The example instructs the compiler to include the current header file only once when the source file will be compiled.
For example, the header file is the file named “MyClass.h”, the source file is the file “MyClass.cpp”.
// File "MyClass.h" #pragma once
⇑
9. Directive #line. Set string to file name in error messages
Using the #line directive instructs the compiler to set (change) the line numbers and file name that are displayed in error messages.
When an error occurs, the compiler remembers the error line number and file name in the __LINE__ and __FILE__ macros, respectively. After the #line directive is called, the value of these macros is changed to the values specified in this directive.
The #line directive can be used in one of two possible general forms:
#line digit_sequence
or
#line digit_sequence [filename]
where
- digit_sequence is an integer constant in the range from 0 to 2147483647 inclusive. This constant specifies the line number and is assigned to the __LINE__ macro after the directive is called;
- filename is an optional parameter that is the name of the file that is displayed in the error message and written in the __FILE__ macro. If filename is omitted, then the previous filename remains unchanged.
The #line directive is commonly used by program generators. In these generator programs, based on the execution (not execution) of some statement, you need to specify the text of the error message and refer to the corresponding source file.
Example.
#include <iostream> using namespace std; int main() { // Print values of macros __LINE__ and __FILE__ cout << "The value of __LINE__: " << __LINE__ << endl; cout << "The value of __FILE__: " << __FILE__ << endl; // Set the new value of the __LINE__ macro #line 12 cout << "The value of __LINE__ after changes: " << __LINE__ << endl; cout << "The value of __FILE__ after changes: " << __FILE__ << endl; // Set the new value of the __LINE__ and __FILE__ macros #line 122 "source2.cpp" cout << "The value of __LINE__ after changes 2: " << __LINE__ << endl; cout << "The value of __FILE__ after changes 2: " << __FILE__ << endl; }
Result
The value of __LINE__: 7 The value of __FILE__: D:\Programs\C++\Project10\Source.cpp The value of __LINE__ after changes: 12 The value of __FILE__ after changes: D:\Programs\C++\Project10\Source.cpp The value of __LINE__ after changes 2: 122 The value of __FILE__ after changes 2: D:\Programs\C++\Project10\source2.cpp
⇑
Related topics
- Macros. Directive #define. Examples
- Conditional compilation. Directives #if, #else, #elif, #endif, #ifdef, #ifndef. The defined operator
⇑