Download presentation
Presentation is loading. Please wait.
Published byCaitlin Doyle Modified over 7 years ago
1
COM S 326X Deep C Programming for the 21st Century Prof. Rozier
Unit 5 – The Preprocessor
2
History of C A number of changes occurred to C from , one of the most important was the introduction of the Preprocessor. Alan Snyder urged for its inclusion: Added file-inclusion available in BCPL and PL/I
3
C Preprocessor Original version was very simple #include #define
Extended by Mike Lesk and John Reiser to include macros with arguments and conditional compilation. Originally an “optional adjunct” to the C language.
4
Invoking the C Preprocessor
Invoked by default. gcc –E file.c –o file.i Invokes just the preprocessor
5
C Preprocessor Contains directives
Special instructions to the preprocessor or compiler on how to process some or all of the source code.
6
#include Many of C’s features are not part of the language, but instead part of the standard library. The standard library is a repository of code available alongside every standard-conformant C compiler. Usually linked in by the compiler unless otherwise specified.
7
#include What #include actually does is cause the preprocessor to include the contents of the file where the #include statement was. Try looking at the output of: gcc –E file.c –o file.i when file.c contains “#include <stdio.h>”
8
#include <header.h>
Two main ways to #include: #include <header.h> #include “header.h” When using <header.h> the compiler searches for the include along the development environment path for standard includes Type: echo | gcc –E –Wp,-v – To find the paths searched. No space!
9
#include When using the form “header.h” the preprocessor searches user-defined locations, including the current directory (usually) for header files before searching the standard path.
10
Include Guards The preprocessor is not intelligent.
It is possible to have the problem of double includes. foo.h includes bar.h main.c includes foo.h and bar.h bar.h is now included twice!
11
Include guards Some compilers support the preprocessor command: #pragma once This isn’t universally supported, so it is non-portable. More commonly we see: #ifndef __HEADER_H__ #define __HEADER_H__ … #endif
12
Include guards Checks if __HEADER_H__ has been defined #ifndef __HEADER_H__ #define __HEADER_H__ void foo(int, int); #endif If not, the compiler includes all this code, including a definition for __HEADER_H__ Otherwise this block is removed by the preprocessor.
13
Include Guard Example Download the include guard example from the course website with the following command: wget Extract the source files with following command: tar –xvf includeguard.tgz Work in groups of 2-3, read through the files and predict their behavior. Run the preprocessor with: gcc –E include_guard.c –o include_guard.i Did the outcome match your expectations? Note: The #warning directive is used to issue compiler messages so you can follow the control flow
14
#define Can be used to define values, macros, or just symbols:
#define iastate Creates the symbol iastate, it exists, but has no interesting definition.
15
#define Can be used to define values, macros, or just symbols:
#define IASTATE Creates the symbol iastate, it exists, but has no interesting definition. By convention, we use uppercase identifiers for the preprocessor.
16
#define Can be used to define values, macros, or just symbols:
#define IASTATE 10 Creates the symbol iastate, and substitutes it for value 10 where it appears.
17
#define Can be used to define values, macros, or just symbols:
#define MAX(x,y) ((x)>(y)?(x):(y)) Creates the symbol MAX, takes two arguments, and builds a pseudofunction. This can be dangerous. The macro just substitutes, but does not evaluate. Can lead to strange results.
18
#define dangers Look at the following two macros:
#define MAXA(x,y) x>y?x:y #define MAXB(x,y) ((x)>(y)?(x):(y)) In groups of 2-3 implement both macros. See how they work with the following: i = MAXA(2,3)+5 j = MAXA(3,2)+5 m = MAXB(2,3)+5 n = MAXB(3,2)+5 What happens? Why? Try running the compiler with –E to examine the output.
19
#define tricks The # symbol has two special tricks with #define:
#define as_string(a) # a #define concatinate(x, y) x ## y Try these #define macros and discuss their results.
20
#define for debug messages
What does the following do? You may try this on the server to explore its outcome. #define num2str(x) str(x) #define str(x) #x #ifdef DEBUG #define debug(msg) fputs(__FILE__ “:” num2str(__LINE__) “ – “ msg, stderr) #else #define debug(msg) #endif
21
Useful Preprocessor Macros and Variables
__FILE__ The name of the current file, as a string literal __LINE__ Current line of the source file, as a numeric literal __DATE__ Current system date, as a string __TIME__ Current system time, as a string __TIMESTAMP__ Date and time (non-standard) __func__ Current function name of the source file, as a string (part of C99) __PRETTY_FUNCTION__ "decorated" Current function name of the source file, as a string (in GCC; non-standard)
22
gcc –D option You can use the compiler to define macros, or symbols:
Useful for debugging! Can be defined using Makefiles!
23
#define for debug messages
Now consider this case with Makefile targets for debug and normal. How would you change to a debug context? #define num2str(x) str(x) #define str(x) #x #ifdef DEBUG #define debug(msg) fputs(__FILE__ “:” num2str(__LINE__) “ – “ msg, stderr) #else #define debug(msg) #endif
24
Compiler directives #error message – halt compilation and produce “message” on the output. #warning message – emit diagnostic message during compilation when encountered.
25
#undef #undef TOKEN – undefines TOKEN.
26
Conditionals on defines
#ifdef TOKEN #ifndef TOKEN Excecutes a block until #endif, #else, #elif encountered if TOKEN is defined, or if it is not defined, respectively.
27
#if, #else, #elif, #endif General conditionals.
#if <expression> - evaluates a block if the expression is nonzero. #else – evaluates a block if the expression for the paired #if was zero. #elif <expression> – evaluates if expression is nonzero, and all previous expressions in the #if block were zero.
28
Advanced preprocessor tricks
X-Macro pattern – NOT RECOMMENDED Shows some of the power of the preprocessor. Examine the code contained on the website in: student-datatype.tgz What does this set of macros do? Execute gcc with the –E flag to examine the output. If you compile the code, use the –c flag to generate an object file, no main means it won’t build a full executable.
29
Advanced preprocessor tricks
X-Macro pattern – NOT RECOMMENDED Shows some of the power of the preprocessor. Examine the code contained on the website in: student-datatype.tgz Why might this be useful? Why might it be dangerous? Why might it be a bad design pattern for C programming?
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.