|
Article on other languages:
|
The C preprocessor (cpp) is the preprocessor for the C programming language. In many C implementations, it is a separate program invoked by the compiler as the first part of translation. The preprocessor handles directives for source file inclusion (#include), macro definitions (#define), and conditional inclusion (#if). The language of preprocessor directives is not strictly specific to the grammar of C, so the C preprocessor can also be used independently to process other types of files. The transformations it makes on its input form the first four of C's so-called Phases of Translation. Though an implementation may choose to perform some or all phases simultaneously, it must behave as if it performed them one-by-one in order. PhasesThe following are the first four (of eight) phases of translation specified in the C Standard:
Including filesThe most common use of the preprocessor is to include another file: #include <stdio.h> int main (void) { printf("Hello, world!\n"); return 0; } The preprocessor replaces the line This can also be written using double quotes, e.g. By convention, include files are given a .h extension, and files not included by others are given a .c extension. However, there is no requirement that this be observed. Occasionally you will see files with other extensions included, in particular files with a .def extension may denote files designed to be included multiple times, each time expanding the same repetitive content.
Conditional compilationThe #define __WINDOWS__ #ifdef __WINDOWS__ #include <windows.h> #else #include <unistd.h> #endif #if VERBOSE >=2 print("trace message"); #endif The first line defines a macro The subsequent code tests if a macro Macro definition and expansionThere are two types of macros, object-like and function-like. Object-like macros do not take parameters; function-like macros do. The generic syntax for declaring an identifier as a macro of each type is, respectively, #define <identifier> <replacement token list> #define <identifier>(<parameter list>) <replacement token list> Note that the function-like macro declaration must not have any whitespace between the identifier and the first, opening, parenthesis. Whenever the identifier appears in the source code it is replaced with the replacement token list, which can be empty. For an identifier declared to be a function-like macro, it is only replaced when the following token is also a left parenthesis that begins the argument list of the macro invocation. The exact procedure followed for expansion of function-like macros with arguments is subtle. Object-like macros were conventionally used as part of good programming practice to create symbolic names for constants, e.g.
#define PI 3.14159
... instead of hard-coding those numbers throughout one's code. However, both C and C++ provide the const directive, which is often better because it gives the value specific scope. An example of a function-like macro is:
#define RADTODEG(x) ((x) * 57.29578)
This defines a radians to degrees conversion which can be written subsequently, e.g. PrecedenceNote that the example macro RADTODEG(x) given above uses normally superfluous parentheses both around the argument and around the entire expression. Omitting either of these can lead to unexpected results. For example:
#define RADTODEG(x) (x * 57.29578)
will expand RADTODEG(a + b) to (a + b * 57.29578)
#define RADTODEG(x) (x) * 57.29578
will expand 1 / RADTODEG(a) to 1 / (a) * 57.29578 neither of which give the intended result. Multiple linesA macro can be extended over as many lines as required using a backslash escape character at the end of each line. The macro ends after the first line which does not end in a backslash. The extent to which multi-line macros enhance or reduce the size and complexity of the source of a C program, or its readability and maintainability is open to debate (there is no experimental evidence on this issue). Techniques such as "supermacros" are occasionally used to address these potential issues.[1] Multiple evaluation of side effectsAnother example of a function-like macro is:
#define MIN(a,b) ((a)>(b)?(b):(a))
Notice the use of the A safer way to achieve the same would be to use a typeof-construct: #define max(a,b) \ ({ typeof (a) _a = (a); \ typeof (b) _b = (b); \ _a > _b ? _a : _b; }) This will cause the arguments to be evaluated only once, and it will not be type-specific anymore. This construct is not legal ANSI C; both the Within ANSI C, there is no reliable general solution to the issue of side-effects in macro arguments. Token concatenationToken concatenation, also called token pasting, is one of the most subtle — and easy to abuse — features of the C macro preprocessor. Two arguments can be 'glued' together using For instance: #define MYCASE(item,id) \ case id: \ item##_##id = id;\ break switch(x) { MYCASE(widget,23); } The line case 23: widget_23 = 23; break; (The semicolon following the invocation of SemicolonsOne stylistic note about the above macro is that the semicolon on the last line of the macro definition is omitted so that the macro looks 'natural' when written. It could be included in the macro definition, but then there would be lines in the code without semicolons at the end which would throw off the casual reader. Worse, the user could be tempted to include semicolons anyway; in most cases this would be harmless (an extra semicolon denotes an empty statement) but it would cause errors in control flow blocks: #define PRETTY_PRINT(msg) \ printf ("Message: '%s'\n", msg); if (n < 10) PRETTY_PRINT("n is less than 10"); else PRETTY_PRINT("n is at least 10"); This expands to give two statements – the intended
Multiple statementsInconsistent use of multiple-statement macros can result in unintended behaviour. The code #define CMDS \ a = b; \ c = d if (var == 13) CMDS; else return; will expand to if (var == 13) a = b; c = d; else return; which is a syntax error (the The macro can be made safe by replacing the internal semicolon with the comma operator, since two operands connected by a comma form a single statement. The comma operator is the lowest precedence operator. In particular, its precedence is lower than the assignment operator's, so that a = b, c = d does not parse as a = (b,c) = d. Therefore, #define CMDS a = b, c = d if (var == 13) CMDS; else return; will expand to if (var == 13) a = b, c = d; else return; The problem can also be fixed without using the comma operator: #define CMDS \ do { \ a = b; \ c = d; \ } while (0) expands to if (var == 13) do { a = b; c = d; } while (0); else return; The if (var == 13) { a = b; c = d; } ; else return; The semicolon in the macro's invocation above becomes an empty statement, causing a syntax error at the Quoting macro argumentsAlthough macro expansion does not occur within a quoted string, the text of the macro arguments can be quoted and treated as a string literal by using the "
#define QUOTEME(x) #x
the code printf("%s\n", QUOTEME(1+2)); will expand to printf("%s\n", "1+2"); This capability can be used with automatic string literal concatenation to make debugging macros. For example, the macro in #define dumpme(x, fmt) printf("%s:%u: %s=" fmt, __FILE__, __LINE__, #x, x) int some_function() { int foo; /* [a lot of complicated code goes here] */ dumpme(foo, "%d"); /* [more complicated code goes here] */ } would print the name of an expression and its value, along with the file name and the line number. Indirectly quoting macro argumentsThe " #define FOO bar #define _QUOTEME(x) #x #define QUOTEME(x) _QUOTEME(x) the code printf("FOO=%s\n", QUOTEME(FOO)); will expand to printf("FOO=%s\n", "bar"); One common use for this technique is to convert the __LINE__ macro to a string. Eg: QUOTEME(__LINE__); is converted to:
"34"
if __LINE__ happens to have the value 34 when QUOTEME() is called. On the other hand _QUOTEME(__LINE__) will expand to "__LINE__" Variadic macrosMacros that can take a varying number of arguments (variadic macros) are not allowed in C89, but were introduced by a number of compilers and standardised in C99. Variadic macros are particularly useful when writing wrappers to variable parameter number functions, such as X-MacrosOne little-known usage-pattern of the C preprocessor is known as "X-Macros". [2][3] An X-Macro is an #include file (commonly using a ".def" extension instead of the traditional ".h") that contains a list of similar macro calls (which can be referred to as "component macros"). The include file is then referenced repeatedly in the following pattern: (Given that the include file is "xmacro.def" and it contains a list of component macros of the style "foo(x, y, z)") #define foo(x, y, z) doSomethingWith(x, y, z); #include "xmacro.def" #undef foo #define foo(x, y, z) doSomethingElseWith(x, y, z); #include "xmacro.def" #undef foo (etc...) The most common usage of X-Macros is to establish a list of C objects and then automatically generate code for each of them. Some implementations also perform any #undefs they need inside the X-Macro, as opposed to expecting the caller to undef them. Common sets of objects are a set of global configuration settings, a set of members of a structure, a list of possible XML tags for converting an XML file to a quickly traversable tree or the body of an enum declaration, although other lists are possible. Once the X-Macro has been processed to create the list of objects, the component macros can be redefined to generate, for instance, accessor and/or mutator functions. Structure serializing and deserializing are also commonly done. Here is an example of an X-Macro that establishes a struct and automatically creates serialize/deserialize functions: (Note: for simplicity, we don't account for endianness or buffer overflows) File: object.def struct_member( x, int ); struct_member( y, int ); struct_member( z, int ); struct_member( radius, double ); File: star_table.c typedef struct { #define struct_member( name, type ) type name; #include "object.def" #undef struct_member } star; void serialize_star( const star *_star, unsigned char *buffer ) { /* Copy each member's data into buffer and move the pointer. */ #define struct_member( name, type ) \ memcpy(buffer, (unsigned char *) &(_star->name), sizeof(_star->name) ); \ buffer += sizeof(_star->name); #include "object.def" #undef struct_member } void deserialize_star( star *_star, const unsigned char *buffer ) { /* Copy each member's data out of buffer and move the pointer. */ #define struct_member( name, type ) \ memcpy((unsigned char *) &(_star->name), buffer, sizeof(_star->name) ); \ buffer += sizeof(_star->name); #include "object.def" #undef struct_member } Often, handlers for individual data types are created and accessed using the token concatenation ("##") and quoting ("#") operators. For instance, the following might be added to the above code: void print_int( int val ) { printf( "%d", val ) } void print_double( double val ) { printf( "%g", val ) } void print_star( const star *_star ) { /* print_##type will be replaced with print_int or print_double */ #define struct_member( name, type ) printf( "%s: ", #name ); print_##type( _star->name ); printf("\n"); #include "object.def" #undef struct_member } The creation of a separate header file can be avoided by creating a single macro containing what would be the contents of the file. For instance, the above defined "object.def" could be replaced with this macro: #define object_def \ struct_member( x, int ); \ struct_member( y, int ); \ struct_member( z, int ); \ struct_member( radius, double ); and then all calls to '#include "object.def"' could be replaced with a simple object_def statement. The above function would become: void print_star( const star *_star ) { /* print_##type will be replaced with print_int or print_double */ #define struct_member( name, type ) printf( "%s: ", #name ); print_##type( _star->name ); printf("\n"); object_def #undef struct_member } A variant which avoids needing to know the names of any expanded sub-macros is to accept the operators as an argument to the list macro: #define object_def(_) \ _( x, int ) \ _( y, int ) \ _( z, int ) \ _( radius, double ) void print_star( const star *_star ) { /* print_##type will be replaced with print_int or print_double */ #define struct_member( name, type ) printf( "%s: ", #name ); print_##type( _star->name ); printf("\n") object_def(struct_member) #undef struct_member } This approach can be dangerous in that the entire macro set is always interpreted as if it was on a single source line, which could encounter compiler limits with complex component macros and/or long member lists. User-defined compilation errors and warningsThe
#error "Gaah!"
This prints "Gaah!" in the compiler output and halts the computation at that point. This is extremely useful for determining whether a given line is being compiled or not. It is also useful if you have a heavily parameterized body of code and want to make sure a particular #ifdef WINDOWS ... /* Windows specific code */ #elif defined(UNIX) ... /* Unix specific code */ #else #error "What's your operating system?" #endif Some implementations provide a non-standard
#warning "Do not use ABC, which is deprecated. Use XYZ instead."
Although the text following the Compiler-specific preprocessor featuresThe C99 introduced a few standard Standard positioning macrosCertain symbols are predefined in ANSI C. Two useful ones are // debugging macros so we can pin down message provenance at a glance #define WHERESTR "[file %s, line %d] " #define WHEREARG __FILE__,__LINE__ printf(WHERESTR ": hey, x=%d\n", WHEREARG, x); This prints the value of Compiler-specific predefined macrosCompiler-specific predefined macros are usually listed in the compiler documentation, although this is often incomplete. The Pre-defined C/C++ Compiler Macros project 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". Some compilers can be made to dump at least some of their useful predefined macros, for example:
As a general-purpose preprocessorSince the C preprocessor can be invoked independently to process files other than those containing to-be-compiled source code, it can also be used as a "general purpose preprocessor" for other types of text processing. One particularly notable example is the now-deprecated imake system; more examples are listed at General purpose preprocessor. See alsoReferences
External linksWikibooks has a book on the topic of
|
||||||||||||||||||||||||||||||||
This article is from Wikipedia. All text is available under the terms of the GNU Free Documentation License.
Mercedes Car
This site monitored by SitePinger.net