CS 2130 Lecture 4 C Preprocessor. Typical "Includes" #include.
-
Upload
james-king -
Category
Documents
-
view
216 -
download
0
Transcript of CS 2130 Lecture 4 C Preprocessor. Typical "Includes" #include.
CS 2130
Lecture 4
C Preprocessor
Typical "Includes"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
Back to Hello World
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
printf(“Hello, World!\n”);
return EXIT_SUCCESS;
}
OK?
Doesn’t printf return something?
• printf(3) returns number of characters transferred• Therefore
>= 0: Success
< 0: Failure
• Probably not worthwhile to check return value • Could do this:
(void)printf(…• Which means ignore return value• BUT THIS COULD BE A REAL BAD IDEA
Some simple streams
• By default we are supplied the following streams
stdin: Keyboard
stdout: Screen
stderr: Screen
So we could do...
if(printf(…) < 0)
{
fprintf(stderr,”printf failed\n”);
/* perhaps exit here? */
}
One slight problem!One slight problem!
So we could do...
if(printf(…) < 0)
{
(void)fprintf(stderr,”printf failed\n”);
/* perhaps exit here? */
}
Does it make sense to use (void) in front of fprintf?Does it make sense to use (void) in front of fprintf?
Three Exceptions
• AllAll function return values must be checked except
(void)fprintf(stderr,…
(void)fflush(stderr);
(void)exit(EXIT_FAILURE);
• WITHOUT FAIL!!!
How you should feel (for the rest of your life) if you forget to check a return value
Darkness falls across the landThe midnight hour is close at handCreatures crawl in search of bloodTo terrorize your neighbor's hood
And whosoever shall be foundWithout the soul for getting down
Must stand and face the hounds of hellAnd rot inside a corpse's shellThe foulest stench is in the air
The funk of forty thousand yearsAnd grizzly ghouls from every tomb
Are closing in to seal your doomAnd though you fight to stay alive
Your body starts to shiverFor no mere mortal can resist
The evil of the 2130 killers
Getting out right now!
exit(EXIT_FAILURE);
• Why not just:
return EXIT_FAILURE;
Macro Processing
• Would like a simple way of performing
if(printf(…) < 0)
{
(void)fprintf(stderr,”printf failed\n”);
/* perhaps exit here? */
}
• Macro Processing could be the answer but first...
When Things Happen
• Key focus of CS 2130 is understanding when things happen
• During Translation (Compilation)• During Execution
Translation (Compilation)
1. Lexical Analysis (Scanning)– Remove Comments– Find Keywords (Reserved Words)
2. Syntax Analysis– Check for structural correctness
3. Semantic Analysis– Concerned with meaning
4. Code Generation
5. Optimization– Time– Space– Global vs. Peephole
Translation (Compilation)
1. Lexical Analysis (Scanning)– Remove Comments– Find Keywords (Reserved Words)
2. Syntax Analysis– Check for structural correctness
3. Semantic Analysis– Concerned with meaning
4. Code Generation
5. Optimization– Time– Space– Global vs. Peephole
FrontEnd
(Analysis)
BackEnd
(Synthesis)
Primary Concern in CS 2130
Translation (Compilation)
1. Lexical Analysis (Scanning)– Remove Comments– Find Keywords (Reserved Words)
2. Syntax Analysis– Check for structural correctness
3. Semantic Analysis– Concerned with meaning
4. Code Generation
5. Optimization– Time– Space– Global vs. Peephole
Parsing
Macro Processing
• When does it occur?– Before step 1. Lexical Analysis– Thus: 0. Macro Processing
• What is it?– Text substitution– Following precise rules
• In C, Macro Processing is done by the C Preprocessor– Takes c source file– Does macro processing– Passes results to C Compiler
Macro Processing?
#define ONE 1
x = y + ONE;
• becomes
x = y + 1;
return DONE;
• remains unchanged
C Preprocessor in Action!
/usr/lib/cpp
gcc -E
• Both run c preprocessor sending output to stdout
/usr/lib/cpp yourprogram.c > someFile.txt
gcc -E yourprogram.c > someFile.txt
Macro Examples
#include <stdio.h>
#include “defs.h”
Looks in /usr/include for stdio.h inserts contents into source file
Looks for defs.h in local directory and inserts contents into source file
Macro Examples
#define EXIT_SUCCESS 0
• Note: Not a constant
const int foo = 42;
• Macro processing uses a symbol table technique
Symbol Table
• Used commonly in any translation operation
Symbol Name Symbol Attributes
foo type, value, address, scope,
lifetime, constant
Example
#define EXIT_SUCCESS 0
return EXIT_SUCCESS;
Example
#define EXIT_SUCCESS 0
return 0;
Why?
EXIT_SUCCESS
• Meaningful self-documentation
Shooting oneself in the foot
#define ONE 1
#define TWO ONE + ONE
int x = ONE, y = TWO;
• becomes
int x = 1, y = ONE + ONE;
• becomes
int x = 1, y = 1 + 1;
Efficiency
• Clearly
y = 2;• is more efficient than
y = 1 + 1;
WRONG!
When do things happen?
• Translation
– “static” stuff
• Execution
– “dynamic” stuff
PreprocessorHere
More foot perforatingint z = TWO * TWO;
• becomes
int z = 1 + 1 * 1 + 1;
• Probably not what was intended!!!
• Parentheses are your friend
#define TWO (ONE + ONE)
#define ONE (1) /* OVERKILL */
Parentheses
• ANSI standard guarantees 32 levels of parentheses nesting*
*enough to satisfy Mr. Scheme: Kurt Eiselt
More shootin’
#define SQUARE(X) (X * X)
int z = SQUARE(2);
int z = SQUARE(x + y);
Fix:
#define SQUARE(X) ((X) * (X))
cuddling
OK?
NOT!
z = SQUARE(x++);
becomes
z = ((x++) * (x++));
What’s the correct answer?
z = x2
z = (x + 1)2
z = x * (x + 1)
z = (x + 1) * (x + 2)
NOT!
z = SQUARE(x++);
becomes
z = ((x++) * (x++));
What’s the correct answer?
z = x2 /* maybe */
z = (x + 1)2 /* probably not */
z = x * (x + 1) /* maybe */
z = (x + 1) * (x + 2) /* Probably not */
Another Possibility
• Make SQUARE a function
int square(int x)
{
return x * x;
}• Now it’s a win!
z = square(x);
z = square(x+y);
z = square(x++);• All work properly• Or is it? Any downside?
What happens?
/* Macro */
SQUARE(x)
.
.
.
SQUARE(x)
.
.
.
SQUARE(x)
/* Function */
square(x)
.
.
.
square(x)
.
.
.
square(x)
What happens?
/* Macro */
((x) * (x))
.
.
.
((x) * (x))
.
.
.
((x) * (x))
What happens?
/* Macro */
((x) * (x))
.
.
.
((x) * (x))
.
.
.
((x) * (x))
/* Function */
pass parameter(s)
call function
.
pass parameter(s)
call function
.
pass parameter(s)
call function
.
square function
return
What happens?
/* Macro */
((x) * (x))
.
.
.
((x) * (x))
.
.
.
((x) * (x))
/* Function */
pass parameter(s)
call function
.
pass parameter(s)
call function
.
pass parameter(s)
call function
.
square function
return
What happens?
/* Macro */
((x) * (x))
.
.
.
((x) * (x))
.
.
.
((x) * (x))
/* Function */
pass parameter(s)
call function
.
pass parameter(s)
call function
.
pass parameter(s)
call function
.
square function
return
What happens?
/* Macro */
((x) * (x))
.
.
.
((x) * (x))
.
.
.
((x) * (x))
/* Function */
pass parameter(s)
call function
.
pass parameter(s)
call function
.
pass parameter(s)
call function
.
square function
return
What happens?
/* Macro */
((x) * (x))
.
.
.
((x) * (x))
.
.
.
((x) * (x))
/* Function */
pass parameter(s)
call function
.
pass parameter(s)
call function
.
pass parameter(s)
call function
.
square function
return
What happens?
/* Macro */
((x) * (x))
.
.
.
((x) * (x))
.
.
.
((x) * (x))
/* Function */
pass parameter(s)
call function
.
pass parameter(s)
call function
.
pass parameter(s)
call function
.
square function
return
What happens?
/* Macro */
((x) * (x))
.
.
.
((x) * (x))
.
.
.
((x) * (x))
/* Function */
pass parameter(s)
call function
.
pass parameter(s)
call function
.
pass parameter(s)
call function
.
square function
return
Macros vs. Functions
• Macros– Text substitution at
Translation (compile) time
– May have problems: e.g. square(x++)
– Will work with different types due to operator overloading
• floats, doubles, ints, …
– Difficult to implement if complex
– Macro optimizes for speed. Why?
• Functions– Separate piece of code– Overhead of passing
arguments and returning results via stack
– Fixes ambiguity problems: e.g. square(x + y) or(x++)
– Function optimizes for space. Why?
Macros vs. Functions
• If the goal is not clearly optimization for speed or time but rather somewhere in-between it’s difficult to know exactly which choice is correct.
• In any event: Don’t try and outwit the compiler!
• A better algorithm is more of an improvement that trying to write tricky code!!!
Inline
• Can write
inline int
square(int x)
{
return x*x;
}• Now square(a++) will work correctly with macro
like performance.• Why use inline?• Compiler will make decision for you if inline omitted
gcc -finline-functions
Questions?