[go: up one dir, main page]

0% found this document useful (0 votes)
59 views36 pages

11 - The Preprocessor

Download as pptx, pdf, or txt
Download as pptx, pdf, or txt
Download as pptx, pdf, or txt
You are on page 1/ 36

The Preprocessor

1
Compilation process in C

Contains 3 different stages:


1. Preprocessor
2. Compiler
3. Linker

Each one is program which process


the output of the previous one

text opcodes

2
Code to executable in C
• The C Preprocessor is not a part of the compiler
• separate step in the compilation process Preprocessor
• preprocessor is just a text substitution tool

• Compilation is the processing of source code files (.c, .cc, or .cpp)


and the creation of an 'object' files (*.o)
Compiler
• You can’t run object files
• The compiler produces the machine language instructions

• Linking creates a single executable file from multiple object files


• linker will complain about undefined functions. If the compiler
could not find the definition for a particular function, it would just
assume that the function was defined in another file.
• The linker may look at multiple files and try to find references for
the functions that weren't mentioned
Linker
3
gcc

• GNU software

GNU: an extensive collection of computer software,


Unix-like design. (but acronym: GNU's Not Unix!)

• gcc is called “compiler”, though it also runs the


preprocessing and (optionally) linking

• Example: run in the shell: gcc hello.c -o hello

4
Compilation process in C
Files with C code has the suffix .c or .h

hello.c
tmpXQ.i
Preprocessor Compiler
)C code(
stdio.h

hello.o
:Executable object(
linker
Hello )file

5
Preprocessor

A single-pass program that:


1. Includes header files
2. Expands macros
3. Controls conditional compilation
4. Removes comments

Outputs –
6 a code ready for the compiler to work on
Preprocessor

We can test what the preprocessor does:

> gcc –E hello.c

will print the C code after running the


preprocessing stage

7
Common Pre-processing Directives

❑ #include

❑ #define

❑ #if ... #else ... #endif

8
#include

9
#include directive
#include "foo.h"
Includes the file ‘foo.h’, starts searching from
the same directory as the current file (the
one that contains the #include directive)

#include <stdio.h>
Includes the file ‘stdio.h’, starts searching from
the standard library directory (part of gcc
installation)
10
#include directive

#include “file”
=
Copy & paste the content of “file” in
this location and continue with pre-
processing

Note that “File.h” is not the same as


“file.h” (Win, Linux)
11
Header files
Header file contains
1. Definitions of data types (typedef,
structs)
2. Declarations of functions & constants that
are shared by multiple modules

#include allows several modules to share


the same set of definitions/declarations

12
Modules & Header files
Shape.h
// declaration
int area(int x1, int y1, int x2,
Complex.c int y2);
...

MyProg.c Shape.c
#include “Shape.h" #include <math.h>
int main() // implementation
{ int area(int x1,int y1,int x2, int y2)
// usage
  area(2,3,5,6); {
} ...
}
13
#define

14
#define directive

#define FOO 1

int x = FOO;

is equivalent (after the preprocessing) to:


int x = 1;

15
#define with arguments - MACRO

#define SQUARE(x) x*x
b = SQUARE (a);

is the same as

b = a*a;

16
#define - caveat

#define SQUARE(x) x*x After preprocessing:


b = SQUARE(a+1); A. b = a^2 +2a +1
B. b = 2a+1
C. b = a^2

A B C
0

17
#define - cautions

#define SQUARE(x) x*x
#define PLUS(x) x+x
b = SQUARE(a+1);
c = PLUS(a)*5;

We actually get the following:


b = a+1*a+1; // b = 2*a + 1
c = a+a*5; // c = 6*a
18
#define - cautions

#define SQUARE(x) x*x
#define PLUS(x) x+x
b = SQUARE(a+1);
c = PLUS(a)*5;

Solution:
#define SQUARE(x) ((x)*(x))
#define PLUS(x) ((x)+(x))
19
#define
Multi-line:
All preprocessor directive effect one line (not c statement).
To insert a line-break, use “\”:

BAD:
#define x (5 +
5)

GOOD:
#define x (5 + \
5)
// x == 10 !
20
Alternative to macros

• Constants
enum { FOO = 1 };
or
const int FOO = 1;

• Functions – inline functions (C99, C++,


will be discussed later on)

21
#if

22
#if directive: conditional compilation
#define DEBUG

#ifdef DEBUG
// compiles only when DEBUG exists (defined)
printf("X = %d\n", X);
#endif

23
Debugging - assert

Example of using conditional compilation


assert.h
#include <assert.h>
// Sqrt(x): compute square root of x
// Assumption: x is non-negative
double sqrt(double x )
{
   assert(x >= 0);  // aborts if x < 0

}
If the program violates the condition, then the
program will abort and print:
assertion "x >= 0" failed: file "Sqrt.c",
line 7 <exception>
25
assert.h

The assertion allows to catch the event


in debug mode, during runtime,
(specifically, not compile-time).

26
assert.h

• Important coding practice

• Declare implicit assumptions

• Checked during debug stage.

The following examples include more preprocessing


directives (#, ##) – read at home about this syntax
27
assert.h
// procedure that prints error message // to disabl
e the printing define the macro NDEBUG
// before the <assert.h> inclusion
void __assert(char* file, int line, char* test);

#ifdef NDEBUG
#define assert(e)     ((void)0)
#else
#define assert(e) \
((e) ? ((void)0) : \
__assert(__FILE__, __LINE__, #e))
#endif
28
Preprocessor: step 1

Preprocessor
#include <assert.h> copy-paste

int main()
{
int i = foo();
assert(i>=0);
return 0;
}

29
Preprocessor: step 2
void __assert(char* file, int line, char* test);

#ifdef NDEBUG Preprocessor
#define assert(e)     ((void)0) cut-out
#else
#define assert(e) \
((e) ? ((void)0) : \
__assert(__FILE__, __LINE__, #e))
#endif

int main()
{
i = foo();
assert(i>=0);
return 0;
}

30
Preprocessor: step 3

void __assert(char* file, int line, char* test);

#define assert(e) \ Preprocessor
copy-paste
((e) ? ((void)0) : \
__assert(__FILE__, __LINE__, #e))

int main()
{
int i = foo();
assert(i>=0);
return 0;
}

31
Preprocessor: output

Without
void __assert(char* file, int line, char* test); this the
code will
not
int main() compile
{ in the
int i = foo(); next
((i>=0) ? ((void)0) : \ stage
__assert(__FILE__, __LINE__, #e))
return 0;
}

32
Preprocessor: step 1

#define NDEBUG Debug/Test


mode vs
#include <assert.h> Release mode

int main()
{
int i = foo();
assert(i>=0);
return 0;
}

33
Defining NDEBUG using the compiler

>> gcc my_program.c –DNDEBUG –o my_exe

This is equivalent for adding at the beginning of the


file, the definition:
#define NDEBUG

34
Preprocessor – summary

❑ Text processing program

❑ Does not know C language rules

❑ Operates before compilation, output passed

to compiler
❑ Can do “copy and paste”, or, “cut”

35
Preprocessor – summary
#include
➢ pastes the included file to current file (.h by convention)
➢ usually contains forward declarations and type definitions

#define
➢ copy-pastes the macro body where macro name appears
➢ used for constants, or simple "functions"

#if
➢ if condition is not fulfilled, “cut” the code
➢ conditional compilation (e.g. debugging code)

36

You might also like