See through C
Module 5
Macros and preprocessors
Tushar B Kute
http://tusharkute.com
The C preprocessor and its role
2
cpp
(C preprocessor)
cc1
(C compiler)
source
program
compiled
code
C compiler (e.g., gcc)
expanded
code
• expand some kinds of characters
• discard whitespace and comments
– each comment is replaced with a single space
• process directives:
– file inclusion (#include)
– macro expansion (#define)
– conditional compilation (#if, #ifdef, …)
#include
• Specifies that the preprocessor should read in the contents of the specified file
– usually used to read in type definitions, prototypes, etc.
– proceeds recursively
• #includes in the included file are read in as well
• Two forms:
– #include <filename>
• searches for filename from a predefined list of directories
• the list can be extended via “gcc –I dir”
– #include “filename”
• looks for filename specified as a relative or absolute path
3
#include : Example
4
a predefined include file that:
• comes with the system
• gives type declarations,
prototypes for library routines
(printf)
where does it come from?
– man 3 printf :
#include: cont’d
• We can also define our own header files:
– a header file has file-extension ‘.h’
– these header files typically contain “public” information
• type declarations
• macros and other definitions
• function prototypes
– often, the public information associated with a code file
foo.c will be placed in a header file foo.h
– these header files are included by files that need that
public information
#include “myheaderfile.h”
5
Macros
• A macro is a symbol that is recognized by the preprocessor and
replaced by the macro body
– Structure of simple macros:
#define identifier replacement_list
– Examples:
#define BUFFERSZ 1024
#define WORDLEN 64
6
Using simple macros
• We just use the macro name in place of the value, e.g.:
#define BUFLEN 1024
#define Pi 3.1416
…
char buffer[BUFLEN];
…
area = Pi * r * r;
7
NOT:
#define BUFLEN = 1024
#define Pi 3.1416;

Example 1
8
Example 2
9
we can “macroize”
symbols selectively
Parameterized macros
• Macros can have parameters
– these resemble functions in some ways:
• macro definition ~ formal parameters
• macro use ~ actual arguments
– Form:
#define macroName(arg1, …, argn) replacement_list
– Example:
#define deref(ptr) *ptr
#define MAX(x,y) x > y ? x : y
10
no space here!
(else preprocessor will
assume we’re defining
a simple macro
Example
11
Macros vs. functions
• Macros may be (slightly) faster
– don’t incur the overhead of function call/return
– however, the resulting code size is usually larger
• this can lead to loss of speed
• Macros are “generic”
– parameters don’t have any associated type
– arguments are not type-checked
• Macros may evaluate their arguments more than once
– a function argument is only evaluated once per call
12
Macros vs. Functions: Argument Evaluation
• Macros and functions may behave differently if an argument is referenced multiple times:
– a function argument is evaluated once, before the call
– a macro argument is evaluated each time it is encountered
in the macro body.
• Example:
13
int dbl(x) { return x + x;}
…
u = 10; v = dbl(u++);
printf(“u = %d, v = %d”, u, v);
prints: u = 11, v = 20
#define Dbl(x) x + x
…
u = 10; v = Dbl(u++);
printf(“u = %d, v = %d”, u, v);
prints: u = 12, v = 21
Dbl(u++)
expands to:
u++ + u++
Properties of macros
• Macros may be nested
– in definitions, e.g.:
#define Pi 3.1416
#define Twice_Pi 2*Pi
– in uses, e.g.:
#define double(x) x+x
#define Pi 3.1416
…
if ( x > double(Pi) ) …
• Nested macros are expanded recursively
14
Header Files
• Have a file extension “.h”
• Contain shared definitions
– typedefs
– macros
– function prototypes
• referenced via “#include” directives
15
Header files: example
16
typedefs
• Allow us to define aliases for types
• Syntax:
typedef old_type_name new_type_name;
• new_type_name becomes an alias for old_type_name
• Example:
– typedef int BasePay;
– typedef struct node {
int value;
struct node *next;
} node;
17
Example
18
defines “wcnode” as an
alias for “struct wc”
we can use “wcnode” in
place of“struct wc”
but not here, since
“wcnode” has not yet
been defined
What if a file is #included multiple times?
19
foo.h
bar1.h bar2.h
bar.c
Conditional Compilation: #ifdef
#ifdef identifier
line1
…
linen
#endif
• macros can be defined by the compiler:
– gcc –D macroName
– gcc –D macroName=definition
• macros can be defined without giving them a specific
value, e.g.:
– #define macroName
20
line1 … linen will be included if
identifier has been defined as a
macro; otherwise nothing will
happen.
Conditional Compilation: #ifndef
#ifndef identifier
line1
…
linen
#endif
21
line1 … linen will be
included if identifier
is NOT defined as a
macro; otherwise
nothing will happen.
Solution to multiple inclusion problem
The header file is written as follows:
#ifndef file_specific_flag
#define file_specific_flag
…contents of file…
#endif
• file_specific_flag usually constructed from the name of the header file:
E.g.: file = foo.h ⇒ flag = _FOO_H_
– try to avoid macro names starting with ‘_’
22
indicates whether or
not this file has been
included already
Another use of #ifdefs
• They can be useful for controlling debugging output
– Example 1: guard debugging code with #ifdefs:
#ifdef DEBUG
…debug message…
#endif
– Example 2: use the debug macro to control what
debugging code appears in the program:
#ifdef DEBUG
#define DMSG(msg) printf(msg) // debugging output
#else
#define DMSG(msg) {} // empty statement
#endif
23
straightforward, but needs
discipline to use consistently
Generalizing #ifdef
#if constant-expression
line1
…
linen
#endif
⇒ line1 … linen included if constant-expression evaluates to a non-zero value
24
Common uses:
• #if 1
or
• #if 0
__LINE__ current line number of the source file
__FILE__ name of the current source file
__TIME__ time of translation
__STDC__ 1 if the compiler conforms to ANSI C
printf("working on %sn", __FILE__);
Predefined Macros
Adapted originally from:
CSc 352
An Introduction to the C Preprocessor
Saumya Debray
Dept. of Computer Science
The University of Arizona, Tucson
debray@cs.arizona.edu
Thank you
This presentation is created using LibreOffice Impress 3.6.2.2

Module 05 Preprocessor and Macros in C

  • 1.
    See through C Module5 Macros and preprocessors Tushar B Kute http://tusharkute.com
  • 2.
    The C preprocessorand its role 2 cpp (C preprocessor) cc1 (C compiler) source program compiled code C compiler (e.g., gcc) expanded code • expand some kinds of characters • discard whitespace and comments – each comment is replaced with a single space • process directives: – file inclusion (#include) – macro expansion (#define) – conditional compilation (#if, #ifdef, …)
  • 3.
    #include • Specifies thatthe preprocessor should read in the contents of the specified file – usually used to read in type definitions, prototypes, etc. – proceeds recursively • #includes in the included file are read in as well • Two forms: – #include <filename> • searches for filename from a predefined list of directories • the list can be extended via “gcc –I dir” – #include “filename” • looks for filename specified as a relative or absolute path 3
  • 4.
    #include : Example 4 apredefined include file that: • comes with the system • gives type declarations, prototypes for library routines (printf) where does it come from? – man 3 printf :
  • 5.
    #include: cont’d • Wecan also define our own header files: – a header file has file-extension ‘.h’ – these header files typically contain “public” information • type declarations • macros and other definitions • function prototypes – often, the public information associated with a code file foo.c will be placed in a header file foo.h – these header files are included by files that need that public information #include “myheaderfile.h” 5
  • 6.
    Macros • A macrois a symbol that is recognized by the preprocessor and replaced by the macro body – Structure of simple macros: #define identifier replacement_list – Examples: #define BUFFERSZ 1024 #define WORDLEN 64 6
  • 7.
    Using simple macros •We just use the macro name in place of the value, e.g.: #define BUFLEN 1024 #define Pi 3.1416 … char buffer[BUFLEN]; … area = Pi * r * r; 7 NOT: #define BUFLEN = 1024 #define Pi 3.1416; 
  • 8.
  • 9.
    Example 2 9 we can“macroize” symbols selectively
  • 10.
    Parameterized macros • Macroscan have parameters – these resemble functions in some ways: • macro definition ~ formal parameters • macro use ~ actual arguments – Form: #define macroName(arg1, …, argn) replacement_list – Example: #define deref(ptr) *ptr #define MAX(x,y) x > y ? x : y 10 no space here! (else preprocessor will assume we’re defining a simple macro
  • 11.
  • 12.
    Macros vs. functions •Macros may be (slightly) faster – don’t incur the overhead of function call/return – however, the resulting code size is usually larger • this can lead to loss of speed • Macros are “generic” – parameters don’t have any associated type – arguments are not type-checked • Macros may evaluate their arguments more than once – a function argument is only evaluated once per call 12
  • 13.
    Macros vs. Functions:Argument Evaluation • Macros and functions may behave differently if an argument is referenced multiple times: – a function argument is evaluated once, before the call – a macro argument is evaluated each time it is encountered in the macro body. • Example: 13 int dbl(x) { return x + x;} … u = 10; v = dbl(u++); printf(“u = %d, v = %d”, u, v); prints: u = 11, v = 20 #define Dbl(x) x + x … u = 10; v = Dbl(u++); printf(“u = %d, v = %d”, u, v); prints: u = 12, v = 21 Dbl(u++) expands to: u++ + u++
  • 14.
    Properties of macros •Macros may be nested – in definitions, e.g.: #define Pi 3.1416 #define Twice_Pi 2*Pi – in uses, e.g.: #define double(x) x+x #define Pi 3.1416 … if ( x > double(Pi) ) … • Nested macros are expanded recursively 14
  • 15.
    Header Files • Havea file extension “.h” • Contain shared definitions – typedefs – macros – function prototypes • referenced via “#include” directives 15
  • 16.
  • 17.
    typedefs • Allow usto define aliases for types • Syntax: typedef old_type_name new_type_name; • new_type_name becomes an alias for old_type_name • Example: – typedef int BasePay; – typedef struct node { int value; struct node *next; } node; 17
  • 18.
    Example 18 defines “wcnode” asan alias for “struct wc” we can use “wcnode” in place of“struct wc” but not here, since “wcnode” has not yet been defined
  • 19.
    What if afile is #included multiple times? 19 foo.h bar1.h bar2.h bar.c
  • 20.
    Conditional Compilation: #ifdef #ifdefidentifier line1 … linen #endif • macros can be defined by the compiler: – gcc –D macroName – gcc –D macroName=definition • macros can be defined without giving them a specific value, e.g.: – #define macroName 20 line1 … linen will be included if identifier has been defined as a macro; otherwise nothing will happen.
  • 21.
    Conditional Compilation: #ifndef #ifndefidentifier line1 … linen #endif 21 line1 … linen will be included if identifier is NOT defined as a macro; otherwise nothing will happen.
  • 22.
    Solution to multipleinclusion problem The header file is written as follows: #ifndef file_specific_flag #define file_specific_flag …contents of file… #endif • file_specific_flag usually constructed from the name of the header file: E.g.: file = foo.h ⇒ flag = _FOO_H_ – try to avoid macro names starting with ‘_’ 22 indicates whether or not this file has been included already
  • 23.
    Another use of#ifdefs • They can be useful for controlling debugging output – Example 1: guard debugging code with #ifdefs: #ifdef DEBUG …debug message… #endif – Example 2: use the debug macro to control what debugging code appears in the program: #ifdef DEBUG #define DMSG(msg) printf(msg) // debugging output #else #define DMSG(msg) {} // empty statement #endif 23 straightforward, but needs discipline to use consistently
  • 24.
    Generalizing #ifdef #if constant-expression line1 … linen #endif ⇒line1 … linen included if constant-expression evaluates to a non-zero value 24 Common uses: • #if 1 or • #if 0
  • 25.
    __LINE__ current linenumber of the source file __FILE__ name of the current source file __TIME__ time of translation __STDC__ 1 if the compiler conforms to ANSI C printf("working on %sn", __FILE__); Predefined Macros
  • 26.
    Adapted originally from: CSc352 An Introduction to the C Preprocessor Saumya Debray Dept. of Computer Science The University of Arizona, Tucson debray@cs.arizona.edu Thank you This presentation is created using LibreOffice Impress 3.6.2.2