The C preprocessor is the first step of the code translation process. It performs some editing tasks before the compiler starts . With Standard C has come a number of useful and powerful techniques that make the preprocessor a genuinely useful tool to the C programmer. The preprocessor is a powerful but must be used carefully (pitfalls)
normally you don’t see the preprocessor output , you can see it by using the -E flag:
# gcc -E samp.c
One duty of the preprocessor is to remove comments, and replace it with blank lines. If any header files are included, these will also appear in the preprocessor output. This can result in a lot of text.
Some preprocessor identifiers:
__LINE__ - Number of line being compiled __FILE__ - Name of file being compiled __DATE__ - Compilation date "mm dd yyyy" __TIME__ - Compilation time "hh:mm:ss" __func__ - Name of the current function
For Example you can use it for debug:
printf("Error in line %d in file %s\n", __LINE__, __FILE__);
Macros and pitfalls:
If we define the following macro:
#define MAX(a,b) (a>b)?a:b
If we use it with simple parameters it will work fine but if we put some complexity it can cause some pitfalls for example:
k = MAX(i++, j++);
Will expand to:
k = ((i++) > (j++)) ? (i++) : (j++));
The result is that one of the arguments will increment twice
Names conflicts
We can define a function with the same name as a predefined macro but we need to use parentheses :
#include<stdio.h> #define max(a,b) (a>b)?a:b+9; int (max)(int a, int b) { return (a > b) ? a : b+99; } int main(void) { int i = 10, j = 100, k1,k2; k1 = (max)(i, j); // function call k2 = max(i, j); // macro call printf("%d\n%d\n",k1,k2); }
The preprocessor will only substitute a macro when the macro is followed by an opening parenthesis (intervening whitespace is allowed). Placing parentheses around the macro name effectively removes the name from the opening parenthesis meaning the preprocessor will leave it alone. It is valid to place parentheses around any C statement without effect
The # operator
The # operator converts macro parameters into strings.
PRINTVAL(ex) printf("%s\n", #ex) PRINTVAL(f + 10); // printf("%s\n", "f + 10");
The ## operator
The ## operator provides a portable way of merging separate tokens into one single token.It takes the macro parameters to its right and left and pastes them together. It cannot be the first or last item in a macro.
#define DISPLAY(x) printf("file%sname = %s\n", #x, file##x##name) const char * file1name = "autoexec.bat"; const char * file2name = "config.sys"; const char * file3name = "command.com"; const char * file4name = "ibmbio.com"; DISPLAY(1); //OK DISPLAY(2); //OK DISPLAY(3); //OK DISPLAY(4); //OK for(i=0;i<4;i++) DISPLAY(i); // Wrong
String Concatenation
Standard C preprocessors concatenate adjacent strings in the input program
printf("hello" "world");
#if
#if can be used to test the value of preprocessor constants. A constant integer expression is evaluated. This may not include sizeof, any casts or any enumerated types.
#if SYMBOL == 4 #if SYMBOL > 4 #if SYMBOL1 == SYMBOL2
The block should ends with #endif and you can use #elif for complex tests
#ifdef and #if defined
#ifdef can be used to determine if a preprocessor symbol has been defined.
#ifdef SYMBOL ... . #endif /* SYMBOL
This may be replaced by the defined operator that is more flexible than #ifdef:
#if defined(SYM_1) && defined(SYM_2) .... #endif
Passing Types Into a Macro
Since the preprocessor does not understand C, the following is possible:
#define SWAP(type, var1, var2) \ { \ type _temp_ = var1; \ var1 = var2; \ var2 = _temp_; \ } SWAP(int, i, j) SWAP(long double, ld1, ld2) SWAP(date, s1, s2)