CPP - The C Preprocessor · The C preprocessor is an important tool when programming in C. It reads...
Transcript of CPP - The C Preprocessor · The C preprocessor is an important tool when programming in C. It reads...
Outline What is it? Directives Macros More more or less interesting characteristics End
CPPThe C Preprocessor
Nils MoschuringPhD Student (LMU)
Nils Moschuring PhD Student (LMU) , CPP 1
Outline What is it? Directives Macros More more or less interesting characteristics End
1 What is it?
2 DirectivesConstant MacrosConstant MacrosFile InclusionConditional CompilationFurther Directives
3 MacrosSimple MacrosMultiline macrosMacro FunctionsMore Problems
4 More more or less interesting characteristicsMacros containing macrosMacros containing macro definitionsVariadic Macros
5 End“Interesting tasks”Overview
Nils Moschuring PhD Student (LMU) , CPP 2
Outline What is it? Directives Macros More more or less interesting characteristics End
What is it?
The C preprocessor is an important tool when programming in C.
It reads a source file, modifies it, following some rules and supplies theresult to the compiler.
Any line which contains a # as the first non-white space character isprocessed by the preprocessor.
There can be white-spaces after the # as well.
Following this # certain C preprocessor directives may be included.
Most compilers can be stopped after preprocessing. Using gcc this isdone via gcc -E.
Nils Moschuring PhD Student (LMU) , CPP 4
Outline What is it? Directives Macros More more or less interesting characteristics End
Constant Macros
Constant macros can be defined using the following directive:
#define name text
name must be an identifier (following C standard). All subsequent encountersof name will replaced with text.This macro expansion or substitution can be stopped using
#undef name
These are commonly used for symbolic constants:
#define PI 3.14#define MAX_LENGTH 1024
This avoids having certain magic numbers or constant values in the code.Thus, if these numbers need to change, this change must only be incorporatedat one place in the code.
Nils Moschuring PhD Student (LMU) , CPP 6
Outline What is it? Directives Macros More more or less interesting characteristics End
Predefined Constant Macros
There are a couple of predefined constant macros which can come in reallyhandy:
__LINE__ integer value, current source code line number__FILE__ constant string, current source file
__FUNCTION__ constant string, current function name__DATE__ constant string “Mmm dd yyyy”, compilation start date__TIME__ constant string “hh:mm:ss”, compilation start time
Handy:
#define HERE printf("HERE: in %s() at %s:%d\n", \__FUNCTION__, __FILE__, __LINE__);
Nils Moschuring PhD Student (LMU) , CPP 7
Outline What is it? Directives Macros More more or less interesting characteristics End
File Inclusion
This is what you all already used a couple of times:
#include <stdlib.h>
Using this special directive, the C preprocessor will copy the content of thewhole stdlib.h file into your source code.Try: output of g++ -E test.c containing only that line.
Nils Moschuring PhD Student (LMU) , CPP 8
Outline What is it? Directives Macros More more or less interesting characteristics End
Conditional Compilation
These directives help
controlling which parts of a program are send to the compiler (and whichare ignored)
building for different platforms
enable or disable debug code
#if, # ifdef, # ifndef constant-expression#else, # elif constant-expression#endif
constant-expression
must evaluate to a constant arithmetic expression and may include macroexpansion.
may include any C operators (==, +, -, ...)
is nonzero the following lines are included until #else, #elif or #endifis encountered.
is a macro name, inclusion happens if the macro is defined.Nils Moschuring PhD Student (LMU) , CPP 9
Outline What is it? Directives Macros More more or less interesting characteristics End
Conditional Compilation: examples
Since comments can not be nested in can be difficult to comment a block ofcode which includes comments.This helps:
#if 0//Unwanted code#endif
Debugging output can be nicely in-/ and excluded:
#define DEBUG
#ifdef DEBUGprintf("This is debug information\n");#endif
also possible
#if defined DEBUGprintf("This is debug information\n");#endif
Nils Moschuring PhD Student (LMU) , CPP 10
Outline What is it? Directives Macros More more or less interesting characteristics End
Conditional Compilation: examples
Includeguards facilitate source code management
my header.h
#ifndef MY_HEADER_FILE#define MY_HEADER_FILE
//code
#endif
Now even multiple
my source.c
#include "my_header.h"
won’t hurt.
Nils Moschuring PhD Student (LMU) , CPP 11
Outline What is it? Directives Macros More more or less interesting characteristics End
#error directive
Syntax
#error message
When the preprocessor encounters this directive compilation stops andmessage is displayed.
Nils Moschuring PhD Student (LMU) , CPP 12
Outline What is it? Directives Macros More more or less interesting characteristics End
#line directive
Syntax
#line linenumber "filename"
This directive changes the values of LINE and FILE to the given values.“filename” is an optional argument.
Nils Moschuring PhD Student (LMU) , CPP 13
Outline What is it? Directives Macros More more or less interesting characteristics End
Simple Macros
The #define directive can be used in more elaborate ways when employingan argument list.
#define name(arg1, arg2, ..., argn) text
There can be no white-space between the name and the argument list.
This macro will be substituted for any occurrence of its name followed bybraces and an appropriate number of arguments.
The supplied arguments will then be substituted for every occurrence intext.
Example:
#define inc(x) x++inc(my_val);
will be replaced by
my_val++;
Easy enough!Nils Moschuring PhD Student (LMU) , CPP 15
Outline What is it? Directives Macros More more or less interesting characteristics End
Simple Macros: Problems
Problematic macro definition:
#define MULTI(x, y) x * y
and use case:
int x = MULTI(1 + 2, 3 + 4);
will be
int x = 1 + 2 * 3 + 4;
after preprocessing!Better version:
#define MULT(x, y) (x) * (y)
Nils Moschuring PhD Student (LMU) , CPP 16
Outline What is it? Directives Macros More more or less interesting characteristics End
Simple Macros: Problems
Another problematic definition:
#define ADD_FIVE(a) (a) + 5
and use case:
int x = ADD_FIVE(3) * 3;
will be
int x = (3) + 5 * 3;
after preprocessing!Better version:
#define ADD_FIVE(a) ((a) + 5)
Always put everything in parentheses
Nils Moschuring PhD Student (LMU) , CPP 17
Outline What is it? Directives Macros More more or less interesting characteristics End
Simple Macros: Multiline macros
In order to enable larger macros expressions involving more sophisticatedfunctions one needs to add a \ to the end of the line.
#define LARGE_MULTI(a,b) ( \(a) \
* \(b) \)
There can not be any white-space after the \!
Nils Moschuring PhD Student (LMU) , CPP 18
Outline What is it? Directives Macros More more or less interesting characteristics End
Macro Functions: Pasting
In order to combine two tokens in a macro evaluation one can use ##.Example:
#define make_func(x) void x##_func() { \printf("Nothing to do\n"); \}
make_func(nils)make_func(student)
will give
void nils_func() { printf("Nothing to do\n"); }void student_func() { printf("Nothing to do\n"); }
Nils Moschuring PhD Student (LMU) , CPP 19
Outline What is it? Directives Macros More more or less interesting characteristics End
Macro Functions: String-izing
When invoking the # operator on an argument token inside of a macro, thepreprocessor will string-ize it by enclosing it with quotation marks.Example:
#define string_it(B) #Bstring_it(nils)
will give
"nils"
Nils Moschuring PhD Student (LMU) , CPP 20
Outline What is it? Directives Macros More more or less interesting characteristics End
Macro Functions: String-izing
More helpful
#define make_func(x) \void x##_func() { \printf("Nothing in" #x "\n"); \}
make_func(nils)
gives
void nils_func() { printf("Nothing in" "nils" "\n"); }
(Consecutive constant strings are always concatenated in C)Even more helpful
#define print_int(x) \printf(#x "has value %d\n", (x)); \
can be used like print int(a+b);
Nils Moschuring PhD Student (LMU) , CPP 21
Outline What is it? Directives Macros More more or less interesting characteristics End
More problems
Lets look at this nice macro using XOR operations:(example taken from www.cprogramming.com by author Alex Allain).
#define SWAP(a, b) a ˆ= b; b ˆ= a; a ˆ= b;
This produces the desired result:
SWAP(x, y);
(we wish to employ an extra semicolon since this macro looks like a functioncall)But what about this:
if(x < 0)SWAP(x, y);
This breaks (two XOR’s will always execute).
Nils Moschuring PhD Student (LMU) , CPP 22
Outline What is it? Directives Macros More more or less interesting characteristics End
More problems: Solution 1
Solution, compound statement:
#define SWAP(a, b) {a ˆ= b; b ˆ= a; a ˆ= b;}
but:
if(x < 0)SWAP(x, y);
elseSWAP(x, z);
won’t work! The semicolon after the closing braces of the macro ends theconditional directive!
Nils Moschuring PhD Student (LMU) , CPP 23
Outline What is it? Directives Macros More more or less interesting characteristics End
More problems: Solution 2
Solution, while loop:
#define SWAP(a,b) do { a ˆ= b; b ˆ= a; a ˆ= b; } while(0)
This will swallow the semicolon. This is actually the best and most accurateway to do this...The loop executes only once and most compilers will not generate extra codefor it.MISSING: Sideeffects in Macro use, i.e.: MAX(x++,y++);
Nils Moschuring PhD Student (LMU) , CPP 24
Outline What is it? Directives Macros More more or less interesting characteristics End
Macros containing macros
You can write macros which contain other macros. The order does not matter,as there is a rescanning process being performed inside the preprocessorexecution.
#define testB testC#define testA testBtestA
results in
testC
Obvious next step:
#define testB testA#define testA testBtestA
sadly (or luckily) results in results in
testA
Nils Moschuring PhD Student (LMU) , CPP 26
Outline What is it? Directives Macros More more or less interesting characteristics End
Macros containing macros: recursion
So why does this not do an infinite loop?
If the name of the macro being replaced is found during this scan ofthe replacement list (not including the rest of the source file’spreprocessing tokens), it is not replaced. Furthermore, if any nestedreplacements encounter the name of the macro being replaced, it isnot replaced. These nonreplaced macro name preprocessing tokensare no longer available for further replacement even if they are later(re)examined in contexts in which that macro name preprocessingtoken would otherwise have beenreplaced. (C++ standard, section 16.3.4 paragraph 2)
This essentially means that every macro can only ever be replaced once ineach line of your source code. This is debatable as the C standard containsinconsistencies in this regard.
Nils Moschuring PhD Student (LMU) , CPP 27
Outline What is it? Directives Macros More more or less interesting characteristics End
Macros containing macros: recursion
#define CAT(a, b) a ## b
#define M_0 CAT(x, y)#define M(a) CAT(M_, a)M(0); // expands to CAT(x, y)
#define N_0() CAT(x, y)#define N(a) CAT(N_, a)()N(0); // expands to xy
(taken from stackoverflow.com, user imre)
Nils Moschuring PhD Student (LMU) , CPP 28
Outline What is it? Directives Macros More more or less interesting characteristics End
Macros containing macro definitions
This is not possible.
#define include_me #include "my_header.h"include_me
will not include my header.h.There is no rescan process for macro definitions, only for emerging macrosubstitutions.
Nils Moschuring PhD Student (LMU) , CPP 29
Outline What is it? Directives Macros More more or less interesting characteristics End
Variadic Macros
Macros can be declared using a variable amount of arguments using a similarsyntax used for functions:
#define eprintf(...) fprintf (stderr, __VA_ARGS__)
Nils Moschuring PhD Student (LMU) , CPP 30
Outline What is it? Directives Macros More more or less interesting characteristics End
Some Problems
Write a preprocessor macro which adds comments to the code.
Write a macro which gives back the number of arguments it as called with.
Solution to the second problem (up to 16 arguments):
#define _NUM_ARGS2(X,X16,X15,X14,X13,X12,X11,X10,X9, \X8,X7,X6,X5,X4,X3,X2,X1,N,...) N
#define NUM_ARGS(...) _NUM_ARGS2(0, __VA_ARGS__ ,16, \15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0)
Nils Moschuring PhD Student (LMU) , CPP 32
Outline What is it? Directives Macros More more or less interesting characteristics End
Overview
We learned about the following Preprocessor directives
#include include a source file#define define a macro#undef undefine a macro#if conditional compilation#ifdef conditional compilation#ifndef conditional compilation#elif conditional compilation#else conditional compilation#endif conditional compilation#line control error reporting#error force an error message#pragma used for implementation-dependent control# null directive; no effect
Nils Moschuring PhD Student (LMU) , CPP 33