Upload
patrick-fowler
View
221
Download
0
Embed Size (px)
Citation preview
1
• Preprocessor– How it works
• File Inclusion: #include
• Macro Definition: #define
• Predefined macros– __LINE__, __FILE__, __DATE__, __TIME__
• Conditional Compilation– #if-#endif– #if-#elif-#else-#endif– #ifdef-#endif– #ifndef-#endif– #error
Today’s Material
2
• Commands that begin with # character are called preprocessor directives– Recall #include, #define
• The following diagram shows the preprocessor’s role in the compilation process
Preprocessor
prog.i
COMPILER
prog.c
PREPROCESSOR (cpp)
Modified C program [text file]
Source code [text file]
prog.o Object Code [binary file]
3
• Input to the preprocessor is a C program containing directives– Preprocessor executes these directives
(commands) and removes them (including comments)
• The output of the preprocessor is an edited version of the C program containing no preprocessor directives– The output of the preprocessor directly goes into
the compiler, which generates the C object code– In fact, the compiler first generates an assembly
code, which is fed into an assembler, which generates the object code
Preprocessor: How it works
4
• Preprocessor directives fall in the following categories
1. File inclusion– #include
2. Macro Definition– #define
3. Conditional Compilation– #if, #ifdef, #ifndef, #elif, #else, #endif
4. Rest of the Directives– #error, #line, #pragma– Specialized and less often used
Preprocessor Directives
5
• Directives always start with # char– # char need not be at the beginning of a line, as
long as only white space precedes it– #include …– #include …
• Any number of spaces and horizontal tab chars may separate the tokens in a directive– #include …– # include …– #include …– # include …
Preprocessor Directive Format(1)
6
• Directives always ends at the first new-line char unless explicitly continued
Preprocessor Directive Format(2)
#define A 2*3 /* ends at the end of the line */
#define B 2* \ /* continues at the next line */3* \ /* continues at the next line */
4 /* ends at the end of the line */
/* Same as #define B 2*3*4 *//* Backslash (\) is the continuation character */
7
• Tells the preprocessor to open a particular file, and “include” its contents as part of the file being processed
#include Directive(1)
#include <stdio.h>main(){ printf(“Hello World\n”);}
• Instructs the preprocessor to open file named stdio.h (located in /usr/include/stdio.h), and bring its contents into the program
% cpp –o hello.i hello.c/* To see what’s included from stdio.h */
8
#include Directive(2)#include <defs.h>/* Search defs.h in standard include directories * i.e., /usr/include, and in any other directory * specified by –I compiler flag * Example: */
% gcc –I/root den.c/* -I/root means that in addition to searching * /usr/include, we want the compiler to also search * /root for any files included with <>, */
#include “defs.h”/* means: Search defs.h in standard include * directories (/usr/include) AND the current * directory */
9
• #define directive defines a macro– a name that represents something else, typically
a constant of some kind
• When the macro is used in the program, the preprocessor expands the macro, replacing it with its definition– This replacement is literal or verbatim
#define Directive(1)
#define N 100int A[N];/* becomes * int A[100]; * after preprocessor processes the C program */
10
#define Example/* Some comment */#define FREEZING_POINT 32#define SCALING_FACTOR 1.8
main(){ float fahrenheit, celsius;
fahrenheit = 75; celsius = (fahrenheit-FREEZING_POINT)/SCALING_FACTOR;}
blankblankblank
main(){ float fahrenheit, celsius;
fahrenheit = 75; celsius = (fahrenheit-32)/1.8;}
Macros Expanded
Comment removed
Macro definitions removed
11
• Macros are expanded literally
#define: Caveats
#define N =100int A[N]; expanded to int A[=100];
#define N 100;int A[N]; expanded to int A[100;];
12
• Simple macros are primarily used to define constants
#define: Primary Usage
#define TRUE 1#define FALSE 0#define PI 3.14159#define DEBUG /* It is OK for the replacement list to be empty */
13
#define: Advantages
• Using #define to create names for constants has several significant advantages– Makes programs easier to read– Makes programs easier to modify– Helps avoid inconsistencies and typos:
• It is difficult to consistently type 3.14159
14
Parameterized Macros
• There must be NO space between macro name and the left parenthesis– If there is a space, the preprocessor assumes
that (..) is part of the replacement list
• x1, x2, x3, …, xn are identifiers – Called the macro’s parameters– Parameters may appear as many times as
desired in the replacement list
#define identifier(x1,x2,x3,..,xn) replacement-list
15
Macro Example#define MAX(x,y) x>y?x:y#define MULT(x,y) x*y
main(){ int i, a=2, b=3; i = MAX(a,b); /* Expanded to i = a>b?a:b; */ i = MULT(a,b); /* Expanded to i = a*b; */ i = MULT(a+2, b+3); /* Expanded to i = a+2*b+3; */ /* This last MULT will produce incorrect result * To fix the problem, you need to parenthesize * the macro as follows: */} /* end-main */
#define MULT(a,b) ((a)*(b))i = MULT(a+2, b+3); /* Expanded to */i = ((a+2)*(b+3)); /* Correct now */
16
• A macro definition can extend to several lines– Must continue the lines by ‘\’ char
Macros (More)
#define SAMPLE(x,y,z,t) (\ (x)+\ (y)+\ (z)+\ (t)\ )
• A macro definition can make use of other macros defined earlier
#define MAX(a,b) ((a)>(b)?(a):(b))#define MAX3(x,y,z) (MAX(x, MAX(y,z)))
17
• A parameterized macro can have an empty parameter list
Macros (More)
#define getchar() fgetc(stdin)
/* This is how getchar is defined in <stdio.h> * () is really not needed, but makes getchar * look like a function. So it is used. */
18
Macros: Important Note
• A parameterized macro is NOT a function
• When the preprocessor encounters a macro, it simply expands it within the source code
• Thus the compiler is NOT even aware that the code has been generated by a macro expansion
19
Advantages of Macros over Functions
1. Program is slightly faster– No overhead of a function call and function
return
2. Macro parameters are generic– Macro parameters do not have types– So we can use the same macro with int, float,
double etc. arguments. E.g., MAX macro defined earlier
20
Disadvantages of Macros over Functions
1. Compiled code will be larger• Since macros are expanded within the source
code, the size of the code gets big
2. Arguments are not type-checked• With functions, the compiler type-checks the
arguments and warns you if there is an error• With macros, this type-checking is NOT possible
3. Macros may evaluate their arguments more than once
n = MAX(i++, j); /* Expanded to */n = (i++ > j)?(i++):(j);/* If i is greater than j, i will be incremented twice, * and n gets the wrong value *//* If MAX was a function, n would get the bigger of i &j and * i would be incremented once. This is due to the fact that * function arguments are evaluated before the function call */
21
Macro Scope
• Macro definitions remain in effect until the end of the file in which they appear
• Macros may be undefined by #undef directive– #undef identifier– #undef is typically used to remove the existing
definition of a macro, so that it can be redefined
22
Predefined Macros(1)• Predefined macros
__LINE__ : Line # of the file being compiled__FILE__ : Name of the file being compiled__DATE__ : Date of compilation “Mmm dd yyyy”__TIME__ : Time of compilation “hh:mm:ss”
printf(This software is compiled on %s at %s\n”, __DATE__, _TIME__);
23
Predefined Macros(2)• We can use _LINE__ and _FILE__ macros to
locate errors#define CHECK_ZERO(divisor)\ if (divisor==0) {\ printf(“**Attempt to divide by zero on line ” \ “%d of file %s**\n”, __LINE__, __FILE__); \ exit(1); /* Terminate the program */ \ } /* end-if */
• Let’s use this macro in our program
CHECK_ZERO(j);k = i/j;
/* if j is zero, CHECK_ZERO will print an error * message and terminate the program */
24
assert macro• C Library provides a similar macro named
assert– Need to include <assert.h>#include <assert.h>
int i, k;i = 0;assert(i!=0);k = 20/i;
• Assert is defined as follows
#define assert(c) \ if (c){ \ printf(“Assertion failed %s\n”, #c); \ } /* end-if */
/* #c makes c a string */
25
Conditional Compilation• C preprocessor recognizes a number of
directives that support conditional compilation– The inclusion or exclusion of a section of a
program text depending on the outcome of a test performed by the preprocessor
• Conditional Compilation Directives are– #if-#endif– #if-#else-#endif– #if-#elif-#else-#endif– #ifdef-#endif– #ifndef-#endif
26
#if-#endif• Suppose there is a section of code that you
want to have compiled based on a condition• Classical example is the debug code that
you insert in your programs– You want to compile your program with the
debug code to see the debug output when debugging
– When the program is all debugged & you do not want to see the debug output anymore, you simply want to avoid compiling that section of the code rather than remove it
– Here is how you can achieve it
27
#if-#endif#define DEBUG 1 /* Simply set DEBUG to 0 if you don’t * want to see the debug output */#if DEBUG
printf(“i: %d\n”, i); printf(“j: %d\n”, j);#endif
• In general, #if directive has the form
#if constant-expression .. .. ..#endif
28
#if-#elif-#else-#endif• #if, #endif can be nested just like ordinary if
statements using #elif, #else directives
#define DEBUG 1
#if DEBUG == 1 .. ..#else .. ..#endif
#define DEBUG 1
#if DEBUG == 1 .. ..#elif DEBUG == 2 .. ..#else .. ..#endif
29
defined operator• Defined operator allows you to test whether
a macro is defined yet– You can use this operator in #if, #elif directives
#if defined(WINDOWS) int g = 3; ..#elif defined(LINUX) int g = 2; ..#elif defined(SOLARIS) int g = 4; ..#else .. ..#endif
• Example: – You want to initiate
a variable/declare a function differently depending on the OS
30
#ifdef, #ifndef• Instead of using defined operator, there is a
shorter way to write the same code using #ifdef & #ifndef
#ifdef WINDOWS int g = 3; ..#endif
#ifdef LINUX int g = 2; ..#endif
#ifdef SOLARIS int g = 4; ..#endif
• Using #ifndef you want the code to get compiled when the macro is NOT defined
31
Other Directives• #error message
– When the preprocessor encounters an #error directive, it prints the error “message”
#if INT_MAX < 100000#error int type is too small!#endif
• #error directive is often found in the #else part of an #if-#elif-#endif series
#if defined(WINDOWS) ..#elif define(LINUX) ..#else#error No OS specified#endif