|
Home >> C Basic Tutorials >> Preprocessorquisite Knowledege 30/05/07 - 1445 Views - Ratings : Preprocessors in C as name signifies is somthing which is done before processing . Before your compiler compiles your code you can give your compiler various instruction on how to handle the source code and its compilation. Major aim of C Preprocessor is to expand the scope of the programming envoirment and to make your code more portable and manageable. Also code developed using preprocessor directives tends to be more maintainable than normal because changes can be introduced with minimum fuss and side effects. Also this topic is very compiler and operating system dependent so we will try to restrict our tutorial domain to the facts which are independent of programming enviorment and applies to every C variants. Contents - 1. Types of Preprocessors 2. #define and #undef 3. #error 4. #include 5. #if,#else,#elif and #endif 6. #ifdef and #ifndef 7. #line 8. #pragma 9. # and ## Preprocessor Operator 10. Predefined Macros In C There are only handfull of preprocessor defined in Standard C and few of them work together in combination yet they allow you to achieve much more without much less effort. In addition your compiler must be providing many more preprocessor to exploit your programming enviorment and programming potential to maximum but keep in mind they produce very specific targeted code when used which is not very portable. Preprocessor can be broadly classified into following groups on the basis of functionality they provide - 1. #define and #undef - Used for defining and undefining MACROS. 2. #error - Used for Debugging 3. #include - Used for combining source code files 4. #if, #else, #elseif, and #endif - Used for conditional compilation similar to if - else statment. 5. #ifdef and #ifndef - Conditional Compilation on basis of #define and #undef 5. #line - Controls the program line and file macros. 6. #pragma - Used for giving compiler instruction. Highly specific to the compiler being used. 7. # and ## - Operators used for stringize and concating operation respectively.
As you can see all types of preprocesor beigns with a #. One inportant prperty is that a preprocessor must be in its own line ie. code below will produce a error - #include <stdio.h> #include <iostream.h>
Now we discuss each of the type indivisually in detail. 2. #define and #undef #define - preprocessor is a very vital of efficient programming. They show the true power and potential application of C Preprocessor. They are use to declare a identifier and associate with a particluar character sequence. Identifier when encounterd in the source is replaced by its respective character sequence in all occurunces. This identifier is known as MACRO. General form of #define preprocessor is - #define MACRO_NAME character_sequence The general standard for creating a macro name is to use capital letters and it is highly recommended you use it because it will help you or someone else differentiate which identifier is a variable and which one is an MACRO. Character sequence defining the code can also be splitted into 2 or more lines by using \ (backslah) at end of the previous line. Also once a macro is defined it can be used in another #define statement to define another macro. C Source code below shows the use of preprocessor described above -
The code above shows the proper use of MACRO but it doesnt show you the true potential of MACROs. Most powrpacked of MACRO is that it lets you create quickly modifiable, portable and maintainable software. This is shown in C Source code below where a MACRO is used to control array size and its input and output, only one change in the macro statement lets you create a new code with diffrent size array. Benfit is you can modify entire program with only one change that also in half a line.
Another power packed feature of MACRO are MACRO FUNCTIONSs , they provide faster program running speed with trade off with program size. Now obsolete because of t he introduction of iniline keyowrd in C99 which does the similar job but with far more ease. Still the use and creation of macro function should be in tool box of every competent C Programmer. In c when one function makes a call to another function it is done in several steps which takes time such as saving of system space, stack loading, stack sheding etc. . But when the macro function is called no such calls are made making program faster. This is because during compiling whenever your compiler find refrence to MACRO FUNCTION in your program its code is copied in place of the function call. This increase size of your program. This a part of ancient rule of size-efficiency trade offs which play tug of war among themselves in a program. Best efficiency and result is achieved from a marco function when they are short and frquently used. Same standard of using capital letters in name of identifier is also followed in MACRO FUNCTIONs. Also observe that the macro function doesnot need a semicolon. C Source code below shows the appropriate use of MACRO FUNCTION -
#undef - this preprocessor is used to undefined a preprocessor previously defined preprocessor to prevent bugs and misuse. Also they are neccesary for proper use of #ifdef and #ifndef preprocessor. This preprocessor in other word is used for localization of MACROs to only to the section of code which require them. Once undefined the macro cannot be no longer refrenced in code after #undef statement. General form of #undef preprocessor is - #undef MACRO_NAME C Source code below shows the potential use of #undef preprocessor -
3. #error The use of this preprocessor is in debugging. Whenever this preprocessor is encountered during compilation the compiler would stop compilation and display the error message associated with the preprocessor in complation Output/Result Window. Depending upon compiler any other debugging information will also accompany your error message. General form of #error is - #error message Also note that message doesnot need to be in double quotes. Following source code display the use of #error preprocessor directive in C -
4. #include #include directive as you can see is used in almost all the programs you can find on C. Though you can write a program with no #include statement using only basic of all operators but you can not possibly achieve anything from this reason being even to most basic of task such as input and output you need standard library function which cannot be used until their respective header file are brough into scope by #include statement. In general #include statment is used to combine source code of your file with source code of external file which may be a standard library code or your self writen code. Code defined in standard library is generally included using header files while your self written code is included using source files. The are two general form of using #include preprocessor - #include <FILENAME> #include "FILENAME" The diffrence between two forms lies in the fact that how the search for the source file is done. When defined in angle brackets search is done in compiler implemented method. Generally it is done in a special directory defined in compiler for including files but may differ with compilers. When defined in double quotes the filename is searched in desired path specified, if no path is defined just the file name is given then the search is done in same folder as source file, if file is still not found it is searched as if it is written in angle brackets. Path is in File name is given as shown in example - For Windows - "C:\\C Source Files\\myfile.cpp") For Linux/Unix - "C:/Source_Files/myfile.cpp" If in any case the file is missing or not found compiler flank an error. Also its a general standard that header files are include in angle bracket while user defined files are include in double quotes. Also its permissible for the include files to further include files and this process is known as nested includes. C standard states that atleast 8 levels while C99 states that 15 levels of nested include should be supported at minimum but generally the compiler supports much more levels. Following C source code shows the #include preprocessor in action -
#if, #else, #elif and #endif are discussed here together because they are almost always used together. They are called conditional compilation preproccesor because they alloq you to seletively compile your code on basis of a bool condition. Condition here must be an constant expression because the condition is evaluate at compile and not runtime so all values in expression should be properly defined before compilation as a result variables cannot be used in the expression. Now we evaluate the function these preprocessors one by one in detail - The general form of using #if statement - #if condition statement1 statement2 . . . statementN. #endif If condition specified in first statement evaluates to be true then the statements between #if and #endif are compiled. Here #endif is used to mark the end of #if block. C Source code below shows the use of #if preprocessor compiler.
#else preprocessor directive is counterpart of #if preprocessor similar to else keyword is counter part of if keyword in conditional statements. It provides the code which compiles when the associative #if condition fails. In other words it provides an alternative compilation path. General form of using #else preprocessor is - #if condition statement1 statement2 . . . statementN. #else statementN+1 statementN+2 . . . statementN+M. #endif
#elif preprocessor can be expanded to #else if and is used to construct a structure similar to if-else ladder. The structure it forms allows multiple compilation option and the control flow keeps on falling on next step in ladder till the conditions are evaluated to be false but if any condtion evaluates to be true rest of the steps in ladder are bypassed on same level. Also diffrent levels can be produced using nesting of ladders. 8 levels in C89 and 63 levels in C99 are minimum supported but like always compilers supports many more levels. Also for efficiency criteria and fast compilation you may want to limit the levels of nesting. If at lowest step in the ladder a #else preprocessor is present then the code assosiated with it compiles if all conditon fails. Also like always #endif preprocessor is used to mark the end of the #elif block. General form of using #else preprocessor is - #if condition
statement1
statement2
.
.
.
statementN.
#elseif
statementN+1
statementN+2
.
.
.
statementN+M.
.
.
.
.
. ... A levels
#else
Statement N+M+A+1
Statement N+M+A+1
.
.
.
Statement N+M+A+Z
#endif
The C Source code given below shows the use of #elif preprocessor. #endif as you can see from above is use to mark of end of #if, #else and #elseof blocks. It is also used to mark end of #ifdef and #ifndef given in the next section. One important property of #endif you must know that it always associate if the nearest conditional compilation preprocessor. This prperty is specially important when you create multiple levels using nesting feature provided in C preprocessor.
#ifdef and #ifndef are also a type of conditinal compilation preprocessor but with a little twist. They work on #ifdef and #ifndef preprocessors and can be used in combination with #else and #elif preprocessor. #ifdef stands for if defined and #ifndef for if not defined. The condition they work on is wether a MACRO is defined or not defined. Code specified by ifdef compiles if the following MACRO is defined while code specified by the #ifndef compiles if the following MACRO is not defined. Both the preprocessors use the the preprocessor #endif to mark the end of the conditonal compilation code. Both #ifdef and #ifndef can be nested similar to if-else statments. It is specified by standard C that any compiler conforming to standard C must provide a minimum of atleast 8 levels of minimum nesting while C99 specifies that a minimum of 63 levels of nesting must be supported. #ifdef can also be written as #if defined and both forn are equivalent. General form of #ifdef preprocessor is - #ifdef MACRO statement1 statement2 . . . statementN. #endif General form of #ifndef preprocessor is - #ifndef MACRO statement1 statement2 . . . statementN. #endif The source code belows shows the purpose of #ifdef and #ifndef preprocessor.
7. #line #line preprocessor is used to change the values of 2 MACROS , _ _LINE _ _ and _ _ FILE _ _. _ _ LINE _ _ - This a dynamic macro which stores the line number of the line presently being compiled. Value is constantly updated as compiler moves forward. _ _ FILE _ _ - This macro stores the file name of the source file being compiled. General form of #line preprocessor is #line number "filename" Here the file name is optional. Filename string replaces the string value of _ _FILE_ _ while the number changes the value of _ _LINE_ _. The major use of #line is in debugging and rare programming situation. Following C Source code shows the #line preprocessor in action - 8. #pragma #pragma is completely compiler defined and varies almost completely from compiler to compiler. Standard C only state this preprocessor but neither defines nor support its use. Compiler is free to defines its how and what. Also C99 supports a new operator _Pragma which provides an alternative to #pragma. Since we are discussing only standard C in this tutorial for more detail please refer your compilers documentation. 9. # and ## Preprocessor Operator # and ## are unique in sense that they are not preprocessor but operators acting on preprocessors.They are a bit different in use and application and are used very rarely allowing preprocessor to handle very rare situations. # is called stringize opertor and turns the argument it precede into a quoted string. Use of # is shown in the C Source code given below and should be properly studied.
## is called the pasting opertor which is used to concates two tokens. Use of ## is shown in the source code shown below -
As you know from above, macros are predefined words which serves special purposes and are created using #define preprocessor. Along with the preprocessor you define yourself every compiler have tons of inbuilt macro you can use. Standard C defines and supports 10 very usefull inbuilt marcos, 5 of them were added by C99. These macros are - _ _LINE_ _ - This a dynamic macro which stores the line number of the line presently being compiled. Value is constantly updated as compiler moves forward. _ _FILE_ _ - This macro stores the file name of the source file being compiled. _ _DATE_ _ - This macro stores the date of compilation in month/day/year format. _ _ TIME _ _ - This macro stores the time of compilation in hour:minute:second format. _ _STDC_ _ - This is a bool macro which have value 1 if the compiler is in accordance with standard C, 0 otherwise. _ _STDC_HOSTED_ _ - This is also a bool macro which has value 1 if operating system is present, 0 if not. This was added by C99. _ _STDC_VERSION_ _ - This is stores the value indicating the version of compiler. It was added by C99 and has minimum value 199901 indicating C99 version 1. _ _STDC_IEC599_ _ - Also added by C99 it is a bool macro is 1 if IEC 60059 floating point arithemetic is supported by compiler, 0 if not. _ _ STDC_IEC599_Complex_ _ - Introduced by C99 it is a bool macro is 1 if IEC 60059 complex arithemetic is supported by compiler, 0 if not. _ _ STDC_ISO_10646_ _- Stores Value representing the year and month of the the ISO/IEC 10646 specification supported by compiler.
Also note that some values maybe larger than that supported by integer so a long integer should be used in the respective case. C Source Code below shows possible use of above macros and should possibly compiled by C99 compiler-
Reader Comments -
|