C preprocessor
The C preprocessor (CPP) is a text file processor that is used with C, C++ and other programming tools. The preprocessor provides for file inclusion (often header files), macro expansion, conditional compilation, and line control. Although named in association with C and used with C, the preprocessor capabilities are not inherently tied to the C language. It can and is used to process other kinds of files.[1] C, C++, and Objective-C compilers provide a preprocessor capability, as it is required by the definition of each language. Some compilers provide extensions and deviations from the target language standard. Some provide options to control standards compliance. For instance, the GNU C preprocessor can be made more standards compliant by supplying certain command-line flags.[2] The C# programming language also allows for directives, even though they cannot be used for creating macros, and is generally more intended for features such as conditional compilation.[3] C# seldom requires the use of the directives, for example code inclusion does not require a preprocessor at all (as C# relies on a package/namespace system like Java, no code needs to be "included"). The Haskell programming language also allows the usage of the C preprocessor, which is invoked by writing Features of the preprocessor are encoded in source code as directives that start with Although C++ source files are often named with a Preprocessor directivesC/C++The following tokens are recognised by the preprocessor in the context of preprocessor directives.
Until C++26, the C++ keywords C#Although C# does not have a separate preprocessor, these directives are processed as if there were one.
Objective-CThe following tokens are recognised by the preprocessor in the context of preprocessor directives.
HistoryThe preprocessor was introduced to C around 1973 at the urging of Alan Snyder and also in recognition of the usefulness of the file inclusion mechanisms available in BCPL and PL/I. The first version offered file inclusion via The C preprocessor was part of a long macro-language tradition at Bell Labs, which was started by Douglas Eastwood and Douglas McIlroy in 1959.[5] PhasesPreprocessing is defined by the first four (of eight) phases of translation specified in the C Standard.
FeaturesFile inclusionTo include the content of one file into another, the preprocessor replaces a line that starts with In the following example code, the preprocessor replaces the line #include <stdio.h>
int main(void) {
printf("Hello, World!\n");
return 0;
}
In this case, the file name is enclosed in angle brackets to denote that it is a system file. For a file in the codebase being built, double-quotes are used instead. The preprocessor may use a different search algorithm to find the file based on this distinction. For C, a header file is usually named with a To prevent including the same file multiple times which often leads to a compiler error, a header file typically contains an include guard or if supported by the preprocessor Conditional compilationConditional compilation is supported via the if-else core directives #ifdef VERBOSE
printf("trace message");
#endif
The following demonstrates more complex logic: #if !(defined __LP64__ || defined __LLP64__) || defined _WIN32 && !defined _WIN64
// code for a 32-bit system
#else
// code for a 64-bit system
#endif
Macro string replacement
A macro specifies how to replace text in the source code with other text. An object-like macro defines a token that the preprocessor replaces with other text. It does not include parameter syntax and therefore cannot support parameterization. The following macro definition associates the text "1 / 12" with the token "VALUE": #define VALUE 1 / 12
A function-like macro supports parameters; although the parameter list can be empty. The following macro definition associates the expression "(A + B)" with the token "ADD" that has parameters "A" and "B". #define ADD(A, B) (A + B)
A function-like macro declaration cannot have whitespace between the token and the first, opening parenthesis. If whitespace is present, the macro is interpreted as object-like with everything starting at the first parenthesis included in the replacement text.
The preprocessor replaces each token of the code that matches a macro token with the associated replacement text in what is known as macro expansion. Note that text of string literals and comments is not parsed as tokens and is therefore ignored for macro expansion. For a function-like macro, the macro parameters are also replaced with the values specified in the macro reference. For example,
A variadic macro (introduced with C99) accepts a varying number of arguments which is particularly useful when wrapping functions that accept a variable number of parameters, such as
Function-like macro expansion occurs in the following stages:
This may produce surprising results: #define HE HI
#define LLO _THERE
#define HELLO "HI THERE"
#define CAT(a,b) a##b
#define XCAT(a,b) CAT(a,b)
#define CALL(fn) fn(HE,LLO)
CAT(HE, LLO) // "HI THERE", because concatenation occurs before normal expansion
XCAT(HE, LLO) // HI_THERE, because the tokens originating from parameters ("HE" and "LLO") are expanded first
CALL(CAT) // "HI THERE", because this evaluates to CAT(a,b)
Undefine macroA macro definition can be removed from the preprocessor context via #undef VALUE
Predefined macrosThe preprocessor provides some macro definitions automatically. The C standard specifies that #define DEBUGPRINT(_fmt, ...) printf("[%s:%d]: " _fmt, __FILE__, __LINE__, __VA_ARGS__)
For the example code below that is on line 30 of file DEBUGPRINT("count=%d\n", count);
The first C Standard specified that Other standard macros include The second edition of the C Standard, C99, added support for One little-known usage pattern of the C preprocessor is known as X-Macros.[6][7][8] An X-Macro is a header file. Commonly, these use the extension Many compilers define additional, non-standard macros. A common reference for these macros is the Pre-defined C/C++ Compiler Macros project, which lists "various pre-defined compiler macros that can be used to identify standards, compilers, operating systems, hardware architectures, and even basic run-time libraries at compile-time." Most compilers targeting Microsoft Windows implicitly define #ifdef __unix__ /* __unix__ is usually defined by compilers targeting Unix systems */
# include <unistd.h>
#elif defined _WIN32 /* _WIN32 is usually defined by compilers targeting 32 or 64 bit Windows systems */
# include <windows.h>
#endif
The example code tests if a macro Line controlThe values of the predefined macros #line 314 "pi.c"
printf("line=%d file=%s\n", __LINE__, __FILE__);
Token stringificationThe stringification operator (a.k.a. stringizing operator), denoted by #define str(s) #s
If stringification of the expansion of a macro argument is desired, two levels of macros must be used. For definition: #define xstr(s) str(s)
#define str(s) #s
#define foo 4
A macro argument cannot be combined with additional text and then stringified. However, a series of adjacent string literals and stringified arguments, also string literals, are concatenated by the C compiler. Token concatenationThe token pasting operator, denoted by #define DECLARE_STRUCT_TYPE(name) typedef struct name##_s name##_t
AbortProcessing can be aborted via the #if RUBY_VERSION == 190
#error Ruby version 1.9.0 is not supported
#endif
WarningAs of C23[10] and C++23[11], a directive to print a message without aborting is provided. Some typical uses are to warn about the use of deprecated functionality. For example: // GNU, Intel and IBM
#warning "Do not use ABC, which is deprecated. Use XYZ instead."
// Microsoft
#pragma message("Do not use ABC, which is deprecated. Use XYZ instead.")
Prior to C23 and C++23, this directive existed in many compilers as a non-standard feature, such as the C compilers by GNU, Intel, Microsoft and IBM. Binary resource inclusionC23 and C++26 introduce the The file to embed is specified the same as for const unsigned char icon_display_data[] = {
#embed "art.png"
};
/* specify any type which can be initialized form integer constant expressions will do */
const char reset_blob[] = {
#embed "data.bin"
};
/* attributes work just as well */
const signed char aligned_data_str[] __attribute__ ((aligned (8))) = {
#embed "attributes.xml"
};
int main() {
return
#embed </dev/urandom> limit(1)
;
}
Non-standard featuresPragmaThe C99 introduced a few standard pragmas, taking the form TrigraphsMany implementations do not support trigraphs or do not replace them by default. AssertionSome Unix preprocessors provided an assertion feature – which has little similarity to standard library assertions.[13] Include nextGCC provides ImportUnlike C and C++, Objective-C includes an In Microsoft Visual C++ (MSVC), there also exists an The Objective-C directive should not be confused with the C++ keyword NullableThe #nullable enable
string? name = null; // OK
string fullName = null; // Warning: possible null assignment
#nullable disable
string test = null; // No warning
This directive does not exist in C/C++. RegionThe #region Helper Methods
void Log(string message)
{
Console.WriteLine(message);
}
#endregion
This directive does not exist in C/C++. Other usesTraditionally, the C preprocessor was a separate development tool from the compiler with which it is usually used. In that case, it can be used separately from the compiler. Notable examples include use with the (deprecated) imake system and for preprocessing Fortran. However, use as a general purpose preprocessor is limited since the source code language must be relatively C-like for the preprocessor to parse it.[2] The GNU Fortran compiler runs "traditional mode" CPP before compiling Fortran code if certain file extensions are used.[16] Intel offers a Fortran preprocessor, fpp, for use with the ifort compiler, which has similar capabilities.[17] CPP also works acceptably with most assembly languages and Algol-like languages. This requires that the language syntax not conflict with CPP syntax, which means no lines starting with Some modern compilers such as the GNU C Compiler provide preprocessing as a feature of the compiler; not as a separate tool. LimitationsText substitution limitationsText substitution has a relatively high risk of causing a software bug as compared to other programming constructs.[19][20]
Consider the common definition of a max macro: #define max(a,b) (((a) > (b)) ? (a) : (b))
The expressions represented by a and b are both evaluated two times due to macro expansion, but this aspect is not obvious in the code where the macro is referenced. If the actual expressions have constant value, then multiple evaluation is not problematic from a logic standpoint even though it can affect runtime performance. But if an expression evaluates to a different value on subsequent evaluation, then the result may be unexpected. For example, given
Failure to bracket arguments can lead to unexpected results. For example, a macro to double a value might be written as: #define double(x) 2 * x
But #define double(x) (2 * (x))
Not general purposeThe C preprocessor is not Turing-complete, but comes close. Recursive computations can be specified, but with a fixed upper bound on the amount of recursion performed.[21] However, the C preprocessor is not designed to be, nor does it perform well as, a general-purpose programming language. As the C preprocessor does not have features of some other preprocessors, such as recursive macros, selective expansion according to quoting, and string evaluation in conditionals, it is very limited in comparison to a more general macro processor such as m4. Phase outDue to its limitations and lack of type safety (as the preprocessor is completely oblivious to C/C++ grammar, performing only text substitutions), C and C++ language features have been added over the years to minimize the value and need for the preprocessor.
For a long time, a preprocessor macro provided the preferred way to define a constant value. An alternative has always been to define a
For a long time, a function-like macro was the only way to define function-like behavior that did not incur runtime function call overhead. Via the
The include directive limits code structure since it only allows including the content of one file into another. More modern languages support a module concept that has public symbols that other modules import – instead of including file content. Many contend that resulting code has reduced boilerplate and is easier to maintain since there is only one file for a module; not both a header and a body. C++20 adds modules, and an For code bases that cannot migrate to modules immediately, C++ also offers "header units" as a feature, which allows header files to be imported in the same way a module would. Unlike modules, header units may emit macros, offering minimal breakage between migration. Header units are designed to be a transitional solution before totally migrating to modules.[26] For instance, one may write See alsoReferences
Sources
External linksWikibooks has a book on the topic of: C Programming/Preprocessor
|
Portal di Ensiklopedia Dunia