Presentation is loading. Please wait.

Presentation is loading. Please wait.

Preprocessor Directives

Similar presentations


Presentation on theme: "Preprocessor Directives"— Presentation transcript:

1 Preprocessor Directives
CST 494/ Gannod

2 Phases of “compilation”
preprocess compile assemble File1.c File1.i File1.s File1.o preprocess compile assemble File2.c File2.i File2.s File2.o link a.out Harry Koehnemann, Computing Studies

3 Harry Koehnemann, Computing Studies
Preprocessor The preprocessor performs tasks such as comment stripping macro expansion File inclusion conditional compilation In-line assembly The preprocessor is controlled by directives which are not part of the C language proper. Each directive begins with a # character and is written on a line by itself (use \ for line continuation). Harry Koehnemann, Computing Studies

4 Harry Koehnemann, Computing Studies
Macro Processing Motivations for using macros: save time (define a macro for a sequences we repeat many times) clarify the meaning of the software (give a symbolic name to a cryptic sequence) make the software easy to change (changing the macro definition, automatically updates the entire program) Harry Koehnemann, Computing Studies

5 Macro Processing cont…
A macro is specified by: #define name replacementText The preprocessor replaces each occurrence of name (except in string constants and character constants) in the source text with replacementText Very efficient – no function call made Caution - textual substitutions are inherently unsafe Harry Koehnemann, Computing Studies

6 Harry Koehnemann, Computing Studies
Object-like macros Object-like macros -- the most common use of #define directives is to give meaningful names to constants (manifest constants) #define PI 3.14 #define BUFFER_SIZE 1024 Substitutions are not made within quoted strings If a macro contains its own name, either directly or via intermediate macros, it is not expanded again when the expansion is examined for more macros. #define foo (4 + foo) Why do we need the parenthesis? What is value w/ out parens? x = foo * 10; Harry Koehnemann, Computing Studies

7 Harry Koehnemann, Computing Studies
Function-like macros Function-like macros look just like function calls To define a function-like macro put () RIGHT after the macro name. E.g, #define init() struct timeval t; \ gettimeofday( &t, NULL ); \ srand48( t.tv_sec ); Functions can have arguments #define min(X, Y) ((X) < (Y) ? (X) : (Y)) Harry Koehnemann, Computing Studies

8 Harry Koehnemann, Computing Studies
Parameters If a parameter name is preceded by a #, it will be expanded into a quoted string (stringification). #define dprint(expr) \ printf(#expr “ = %g\n”, expr) Arguments can be concatenated using the ## operator #define paste(front, back) front ## back Harry Koehnemann, Computing Studies

9 Swallowing the semicolon
How does the following get expanded? #include <stdio.h> #define show(x,s) printf("%d", x); \ printf(s); int main(){ int x; printf("Enter an integer: "); scanf( "%d", &x); if( x % 2 ) show(x, " is odd\n"); else show(x, " is the magic number!\n"); } Harry Koehnemann, Computing Studies

10 Harry Koehnemann, Computing Studies
The do-while solution we can “swallow” the semi-colon by doing a crazy kluge with a do-while loop because it is a SINGLE statement (that ends in a semi-colon) write the macro as #define macroName()do{statement1; \ statement2; \ statementn;} \ while(0) Harry Koehnemann, Computing Studies

11 Harry Koehnemann, Computing Studies
Variadic Macros A function-like macro can be declared to accept a variable number of arguments: #define eprintf(...) fprintf (stderr, __VA_ARGS__) All the tokens in its argument list after the last named argument, including any commas, become the variable argument. This sequence of tokens replaces the identifier __VA_ARGS__ in the macro. Harry Koehnemann, Computing Studies

12 Harry Koehnemann, Computing Studies
Variadic Example Macro: #define eprintf(...) fprintf (stderr, __VA_ARGS__) Reference to macro: eprintf ("%s:%d: ", input_file, lineno) Will be expanded to: fprintf (stderr, "%s:%d: ", input_file, lineno) Harry Koehnemann, Computing Studies

13 Harry Koehnemann, Computing Studies
Including Files The #include directive allows you to “insert” source code from other files. The #include is most often used with header files. System header files declare the interfaces to parts of the operating system. They are specified with<> around name. #include <stdio.h> You can create your own header files that contain macros and declarations for interfaces common to the source files of your program. #include “myheader.h” Including a header file produces the same results as copying the header file into each source file that needs it. Harry Koehnemann, Computing Studies

14 Harry Koehnemann, Computing Studies
myHeader.h #include <stdio.h> #include "myHeader.h" int main(){ int x; x = guess(); if( x < MAGIC_NUM ) show(x, " is too low\n"); else if( x > MAGIC_NUM ) show(x, " is too high\n"); else show(x, " is the magic number!\n"); } #include "functs.c" #define MAGIC_NUM 13 #define MIN 1 #define MAX 100 #define show(x,s) \ do{ printf("%d", x); \ printf(s);} \ while(0) int guess(); functs.c int guess(){ int x = MIN -1; printf("Guess a positive integer between %d and %d: ", MIN, MAX ); scanf("%d", &x ); while( x < MIN || x > MAX ){ printf("Invalid – guess must between %d and %d: ", MIN, MAX ); } return x; Harry Koehnemann, Computing Studies

15 Harry Koehnemann, Computing Studies
Undefining macros If a macro ceases to be useful, it may be undefined with the #undef directive. #undef takes a single argument, the name of the macro to undefine. a new macro (that has same name as old) can be defined later in the code, and its definition will be used after the point of its definition. Harry Koehnemann, Computing Studies

16 Issues with separate compilation
In the guessGame example, what happens if we try to compile “functs.c” alone (using –c flag)? WHY? Solution: #include “myHeader.h” in functs.c. What happens when we try to compile functs.c alone? What happens when we compile guessGame.c? Harry Koehnemann, Computing Studies

17 Motivation for separate compilation
#include <stdio.h> #include "myTypes.h" void init( List * myList ){ myList->head = NULL; myList->tail = NULL; myList->length = 0; } void add( List * myList, int val ){ Node * n = (Node*) malloc(sizeof(Node)); n->data = val; n->next = myList->head; myList->head = n; (myList->length)++; void print( List myList ){ int i; Node * temp = myList.head; for( i = 0; i < myList.length - 1; i++ ){ printf( "%d -> ", temp->data ); temp = temp->next; } printf( "%d", temp->data ); #include<stdio.h> #include "myTypes.h" int main(){ List L; init( &L ); add( &L, 2 ); add( &L, 7 ); printf(" L = " ); print( L ); printf( "\n" ); } #include "listFuncts.c" Harry Koehnemann, Computing Studies

18 Harry Koehnemann, Computing Studies
myTypes.h typedef struct Node_struct{ int data; struct Node_struct * next; } Node; typedef struct List_struct{ Node * head; Node * tail; int length; } List; void add( List * , int ); void print( List ); void init( List * ); Harry Koehnemann, Computing Studies

19 Harry Koehnemann, Computing Studies
Bitwise Example #ifndef BITWISE_H_ #define BITWISE_H_ /* A 16-bit integer number is broken up as follows: * #bits position * 1 0 read permission * write permission * user id * unused - should always be 0 * character byte */ #define SET_READABLE 0x1 #define SET_WRITEABLE 0x2 #define SET_USERID(id) (id<<2) #define SET_CHAR(c) (c << 8) #define READ_MASK 0x0001 #define WRITE_MASK 0x0002 #define USERID_MASK 0x003C #define CHAR_MASK 0xFF00 #define IS_READABLE(desc) ( (desc & READ_MASK) >> 0) #define IS_WRITEABLE(desc) ( (desc & WRITE_MASK) >> 1) #define USERID(desc) ( (desc & USERID_MASK) >> 2) #define CHAR_VALUE(desc) ( (desc & CHAR_MASK) >> 8) #endif /*BITWISE_H_*/ Harry Koehnemann, Computing Studies

20 Harry Koehnemann, Computing Studies
Bitwise Example #include <stdio.h> #include "bitwise.h" void displayValues(int desc); // declare function int main() { displayValues(0x413F); // Who can read this!!! displayValues(SET_READABLE | SET_WRITEABLE | SET_USERID(0xF) | SET_CHAR('A')); displayValues(SET_WRITEABLE | SET_CHAR('B')); return 0; } void displayValues(int desc) { printf("Descriptor is %x (read:%d, write:%d, userid:%d, char:%c)\n", desc, IS_READABLE(desc), IS_WRITEABLE(desc), USERID(desc), CHAR_VALUE(desc)); Descriptor is 413f (read:1, write:1, userid:15, char:A) Descriptor is 4103 (read:0, write:1, userid:0, char:B) Harry Koehnemann, Computing Studies

21 Conditional Compiling
This preprocessing feature lets us designate parts of a program which may or may not be compiled. #ifdef symbol .... {#else} #endif #ifndef symbol .... {#else} #endif One common application of conditional compilation is for inclusion/exclusion of debugging statements Another common application is to “protect” information in header files that might be included in multiple source files. Harry Koehnemann, Computing Studies

22 Conditional Compiling cont...
Other directives: #if #elif #else #endif Example: #if SYSTEM == SYSV #define HDR “sysv.h” #elif SYSTEM == BSD #define HDR “bsd.h” #else #define HDR “default.h” #endif #include HDR Harry Koehnemann, Computing Studies

23 Harry Koehnemann, Computing Studies
#pragma directives A #pragma directive is used to provide additional information to the compiler (beyond what is conveyed in the language itself) A pragma has the following form: #pragma characterSequence characterSequence is not subject to macro substitution E.g., #pragma GCC system_header tells the compiler to treat the current file as if it came from a system header #pragma align alignment (variable [, variable]...) tells the compiler to increase the minimum alignment of each variable to alignment Harry Koehnemann, Computing Studies

24 Harry Koehnemann, Computing Studies
References Harry Koehnemann, Computing Studies


Download ppt "Preprocessor Directives"

Similar presentations


Ads by Google