Topics 1. Preprocessor Directives include define o Macro o Other usages pragma 2. Header Files
C Preprocessor Directives Introduction and Motivation  The first step in compiling any C program is the preprocessor, a sort of automated editor that modifies (a copy of ) the source code before passing it on to the compiler to translate into machine language code.  One of the tasks of the preprocessor is to strip off all comments, which the compiler ignores.  The preprocessor also responds to directives in the code, which give the preprocessor explicit instructions on how to edit the source code before passing it on to the compiler. The #include Preprocessor Directive  The #include directive causes the preprocessor to read in the contents of some other file, which may in turn #include some other file(s), etc. Motivation:  Small programs, containing only a main( ) function and few if any additional function can be kept all in one file.  For programs of any significant size, however, it is better to break the program up into separate files. Some of the advantages of this approach are: o When changes are made to part of the program, it is only necessary to recompile the file(s) that have been changed. Any other files can be re-used without having to be recompiled. o Certain functions and their special data types may be used by more than one program. This is much easier if these functions and their data types are defined in their own files, separate from main( ).  These routines can be inserted into libraries, and/or distributed to others in binary compiled format. Application of #include  The preprocessor reads C program source code files and performs some preliminary processing on them before passing along the modified versions to the full compiler.  In particular, the #include directive tells the pre-processor to go read in the contents of a particular file, and place the contents inside the file being compiled at this point. The effect is as if you copied one file and pasted it into the other. (Note that the original file is not actually changed. A temporary copy is made, modified by the preprocessor, and then passed
along to the compiler. The compiler itself never sees the unmodified original. )  Most commonly the #inlcuded files have a ".h" extension, indicating that they are header files.  There are two common formats for #includes, as follows: o #include < libraryFile.h > // The angle brackets say to look in the standard system directories o #include " personalHeaders.h" // The quotation marks say to look in the current directory.  Directories and disk drive information is legal, but discouraged since it is not portable: o #include <C:Program FilesLibrariesIncludessomefile.h > // Too specfiic o #include <sys/types.h> // Common subdirectory, relative to the standard locations. Typical Contents of #included Files 1. Defined Types and Data Structures  structs  enums  typedefs 2. Defined Constants  The #define preprocessor directive can be used to globally replace a word with a number. (i.e., text substitution)  It acts as if an editor did a global search-and-replace edit of the file.  So for example, if you have: #define MAXARRAYSIZE 100  then everywhere that the preprocessor finds MAXARRAYSIZE, it will replace it with 100. So: int numbers[ MAXARRAYSIZE ]; for( int i = 0; i < MAXARRAYSIZE; i++ )  become: int numbers[ 100 ]; for( int i = 0; i < 100; i++ )
 Beware of two common errors with #defines - Adding extra characters that don't belong. For example: #define MAXARRAYSIZE = 100 #define MAXARRAYSIZE 100;  results in : int numbers[ = 100 ]; int numbers[ 100; ];  Leading to the unexpected error messages: o Error: = not expected o Error: missing ]  Preprocessor defines can incorporate previously defined variables, as in: #define PI 3.14159 #define PI2 ( PI / 2.0 ) 3. Function Prototypes  Adding function prototypes into header files ensures that all functions agree on what the prototype should be, and if it changes, it only needs to be changed in one place. 4. Declared ( not Defined ) Global Variables  The "extern" keyword on a global variable declaration lets the compiler know that the variable exists, but does not allocate any space for it.  Exactly one file in the program must define the variable ( allocate space and initialize if appropriate ), by declaring it without the extern keyword.  So in the .h file that is #included by everybody: extern int maxAssignments, maxScores[ ]; // Note no size given for the array  and then in exactly one .c file: int maxAssignments = 7, maxScores[ maxAssignments ]; // Here a size is required and initialization is allowed Macros
Avoiding Circular Includes  #included header files often #include other header files in a daisy-chain like manner.  In order to avoid an infinite cycle of circular includes, the pre-processor directives #ifndef, #define, and #endif are often used. Consider this example for the header file named "headerFile.h": #ifndef HEADERFILE_H #define HEADERFILE_H // Normal Header File Contents // May #include other files, which may #include this one eventually #endif The #define Preprocessor Directive  The #define directive is used to "define" preprocessor "variables", which can then be used in one of three ways. Text substitution is already discussed above. The rest two ways are shown in the following two sections. Using #define For Boolean Testing  Sometimes the preprocessor only needs to know whether a particular preprocessor variable is defined or undefined.  In this case, use #define and #undef to turn such variables "on" or "off"  The status of a preprocessor variable can be tested with #ifdef or #ifndef, either of which starts a block of code that must be terminated by a matching #endif. ( #elif and #else can also be used, if you need more complicated if- else type blocks. )  For example, you may have a number of printing statements that you only want active when debugging. You can "protect" them in a "ifdef" block as follows: #ifdef DEBUG printf( "Now beginning loop %d with x = %f, y = %f, and z = %fn", i, x, y, z ); #endif  Then you can turn all such blocks on or off at once using
#define DEBUG  or #undef DEBUG  Boolean type preprocessor variables can be defined from the UNIX command-line using the "-D" flag to gcc, i.e. "-DDEBUG". Using #define To Define Macros  In addition to simple variable substitutions, it is also possible to create pre- processor macros that take arguments.  Macros operate much like functions, but because they are expanded in place they are generally faster, since they do not invoke the overhead of transferring control over to a function and then transferring control back again.  However there are some potential dangers when using macros instead of functions, as described below.  Example: #define PI 3.14159 #define SQUARE(x) x * x ... area = PI * SQUARE( radius );  which will be seen by the compiler as: area = 3.14159 * radius * radius;  Note: It is very important to include parentheses around all variables used in a preprocessor macro, as well as around the entire definition.  Exercise: What will be the effects of the following? Which is correct? A. #define SQUARE(x) x * x B. ... C. abSquared = SQUARE( a + b ); D. #define SQUARE(x) (x) * (x) E. ... F. a_over_b_squared = a / SQUARE( b ); G. #define SQUARE(x) ( (x) * (x) ) H. ... I. answer = SQUARE( a + b ) / SQUARE( b );
 Landmine! Do not use auto-increment or decrement operators, assignment statements, or function calls in combination with preprocessor macros. Consider: for( i = 0; i < 10; ) printf( "%d squared = %dn, i, SQUARE( i++ ) );  Preprocessor macros can take multiple arguments: #define A_MOD_B(a,b) ( (a) % (b) )  Preprocessor macros can also make use of previously defined macros #define MAX(a,b) ( (a) > (b) ? (a) : (b) ) #define MAX3(a,b,c) ( ((a) > (b)) ? MAX((a),(c)) : MAX((b),(c)) ) // or #define MAX3(a,b,c) ( MAX((a), MAX((b),(c)) )  Preprocessor macros can span multiple lines only if the end of line is explicitly escaped: #define MIN(a,b) ( (a) < (b) ? (a) : (b) )  Note that macros do not check the types of their arguments, which can have both good and bad consequences. Predefined Macros  There are a number of macros automatically pre-defined by the compiler, inlcuding the following list. Note that each one begins and ends with TWO underscore characters: o __LINE__ - The line number of the current file being compiled o __FILE__ - The name of the current file being compiled o __DATE__ - The current date o __TIME__ - The current time The #pragma Preprocessor Directive  The #pragma directive is used to give the preprocessor ( and compiler ) specific details on exactly how to compile the program. For example, specific compiler warnings can be ignored, or warning levels changed up or down for different sections of code.  Examples: o #pragma page( ) // Forces a form feed in the listing
o #pragma warning( disable: 2044 ) // Disables warning number 2044 o #pragma line 100 // Sets the current line number to 100 for listing and reporting purposes. Header Files  A header file is a file with extension .h which contains C function declarations and macro definitions to be shared between several source files. There are two types of header files: the files that the programmer writes and the files that comes with your compiler.  You request to use a header file in your program by including it with the C preprocessing directive #include, like you have seen inclusion of stdio.h header file, which comes along with your compiler.  Including a header file is equal to copying the content of the header file but we do not do it because it will be error-prone and it is not a good idea to copy the content of a header file in the source files, especially if we have multiple source files in a program.  A simple practice in C or C++ programs is that we keep all the constants, macros, system wide global variables, and function prototypes in the header files and include that header file wherever it is required.  Include Operation  The #include directive works by directing the C preprocessor to scan the specified file as input before continuing with the rest of the current source file. The output from the preprocessor contains the output already generated, followed by the output resulting from the included file, followed by the output that comes from the text after the #include directive. For example, if you have a header file header.h as follows –  char *test (void); and a main program called program.c that uses the header file, like this –  int x;  #include "header.h"   int main (void) {  puts (test ());  }
the compiler will see the same token stream as it would if program.c read.  int x;  char *test (void);   int main (void) {  puts (test ());  }  Once-Only Headers  If a header file happens to be included twice, the compiler will process its contents twice and it will result in an error. The standard way to prevent this is to enclose the entire real contents of the file in a conditional, like this −  #ifndef HEADER_FILE  #define HEADER_FILE   the entire header file file   #endif  This construct is commonly known as a wrapper #ifndef. When the header is included again, the conditional will be false, because HEADER_FILE is defined. The preprocessor will skip over the entire contents of the file, and the compiler will not see it twice.  Computed Includes  Sometimes it is necessary to select one of the several different header files to be included into your program. For instance, they might specify configuration parameters to be used on different sorts of operating systems. You could do this with a series of conditionals as follows −  #if SYSTEM_1  # include "system_1.h"  #elif SYSTEM_2  # include "system_2.h"  #elif SYSTEM_3  ...  #endif

6 preprocessor macro header

  • 1.
    Topics 1. Preprocessor Directives include define oMacro o Other usages pragma 2. Header Files
  • 2.
    C Preprocessor Directives Introductionand Motivation  The first step in compiling any C program is the preprocessor, a sort of automated editor that modifies (a copy of ) the source code before passing it on to the compiler to translate into machine language code.  One of the tasks of the preprocessor is to strip off all comments, which the compiler ignores.  The preprocessor also responds to directives in the code, which give the preprocessor explicit instructions on how to edit the source code before passing it on to the compiler. The #include Preprocessor Directive  The #include directive causes the preprocessor to read in the contents of some other file, which may in turn #include some other file(s), etc. Motivation:  Small programs, containing only a main( ) function and few if any additional function can be kept all in one file.  For programs of any significant size, however, it is better to break the program up into separate files. Some of the advantages of this approach are: o When changes are made to part of the program, it is only necessary to recompile the file(s) that have been changed. Any other files can be re-used without having to be recompiled. o Certain functions and their special data types may be used by more than one program. This is much easier if these functions and their data types are defined in their own files, separate from main( ).  These routines can be inserted into libraries, and/or distributed to others in binary compiled format. Application of #include  The preprocessor reads C program source code files and performs some preliminary processing on them before passing along the modified versions to the full compiler.  In particular, the #include directive tells the pre-processor to go read in the contents of a particular file, and place the contents inside the file being compiled at this point. The effect is as if you copied one file and pasted it into the other. (Note that the original file is not actually changed. A temporary copy is made, modified by the preprocessor, and then passed
  • 3.
    along to thecompiler. The compiler itself never sees the unmodified original. )  Most commonly the #inlcuded files have a ".h" extension, indicating that they are header files.  There are two common formats for #includes, as follows: o #include < libraryFile.h > // The angle brackets say to look in the standard system directories o #include " personalHeaders.h" // The quotation marks say to look in the current directory.  Directories and disk drive information is legal, but discouraged since it is not portable: o #include <C:Program FilesLibrariesIncludessomefile.h > // Too specfiic o #include <sys/types.h> // Common subdirectory, relative to the standard locations. Typical Contents of #included Files 1. Defined Types and Data Structures  structs  enums  typedefs 2. Defined Constants  The #define preprocessor directive can be used to globally replace a word with a number. (i.e., text substitution)  It acts as if an editor did a global search-and-replace edit of the file.  So for example, if you have: #define MAXARRAYSIZE 100  then everywhere that the preprocessor finds MAXARRAYSIZE, it will replace it with 100. So: int numbers[ MAXARRAYSIZE ]; for( int i = 0; i < MAXARRAYSIZE; i++ )  become: int numbers[ 100 ]; for( int i = 0; i < 100; i++ )
  • 4.
     Beware oftwo common errors with #defines - Adding extra characters that don't belong. For example: #define MAXARRAYSIZE = 100 #define MAXARRAYSIZE 100;  results in : int numbers[ = 100 ]; int numbers[ 100; ];  Leading to the unexpected error messages: o Error: = not expected o Error: missing ]  Preprocessor defines can incorporate previously defined variables, as in: #define PI 3.14159 #define PI2 ( PI / 2.0 ) 3. Function Prototypes  Adding function prototypes into header files ensures that all functions agree on what the prototype should be, and if it changes, it only needs to be changed in one place. 4. Declared ( not Defined ) Global Variables  The "extern" keyword on a global variable declaration lets the compiler know that the variable exists, but does not allocate any space for it.  Exactly one file in the program must define the variable ( allocate space and initialize if appropriate ), by declaring it without the extern keyword.  So in the .h file that is #included by everybody: extern int maxAssignments, maxScores[ ]; // Note no size given for the array  and then in exactly one .c file: int maxAssignments = 7, maxScores[ maxAssignments ]; // Here a size is required and initialization is allowed Macros
  • 5.
    Avoiding Circular Includes #included header files often #include other header files in a daisy-chain like manner.  In order to avoid an infinite cycle of circular includes, the pre-processor directives #ifndef, #define, and #endif are often used. Consider this example for the header file named "headerFile.h": #ifndef HEADERFILE_H #define HEADERFILE_H // Normal Header File Contents // May #include other files, which may #include this one eventually #endif The #define Preprocessor Directive  The #define directive is used to "define" preprocessor "variables", which can then be used in one of three ways. Text substitution is already discussed above. The rest two ways are shown in the following two sections. Using #define For Boolean Testing  Sometimes the preprocessor only needs to know whether a particular preprocessor variable is defined or undefined.  In this case, use #define and #undef to turn such variables "on" or "off"  The status of a preprocessor variable can be tested with #ifdef or #ifndef, either of which starts a block of code that must be terminated by a matching #endif. ( #elif and #else can also be used, if you need more complicated if- else type blocks. )  For example, you may have a number of printing statements that you only want active when debugging. You can "protect" them in a "ifdef" block as follows: #ifdef DEBUG printf( "Now beginning loop %d with x = %f, y = %f, and z = %fn", i, x, y, z ); #endif  Then you can turn all such blocks on or off at once using
  • 6.
    #define DEBUG  or #undefDEBUG  Boolean type preprocessor variables can be defined from the UNIX command-line using the "-D" flag to gcc, i.e. "-DDEBUG". Using #define To Define Macros  In addition to simple variable substitutions, it is also possible to create pre- processor macros that take arguments.  Macros operate much like functions, but because they are expanded in place they are generally faster, since they do not invoke the overhead of transferring control over to a function and then transferring control back again.  However there are some potential dangers when using macros instead of functions, as described below.  Example: #define PI 3.14159 #define SQUARE(x) x * x ... area = PI * SQUARE( radius );  which will be seen by the compiler as: area = 3.14159 * radius * radius;  Note: It is very important to include parentheses around all variables used in a preprocessor macro, as well as around the entire definition.  Exercise: What will be the effects of the following? Which is correct? A. #define SQUARE(x) x * x B. ... C. abSquared = SQUARE( a + b ); D. #define SQUARE(x) (x) * (x) E. ... F. a_over_b_squared = a / SQUARE( b ); G. #define SQUARE(x) ( (x) * (x) ) H. ... I. answer = SQUARE( a + b ) / SQUARE( b );
  • 7.
     Landmine! Donot use auto-increment or decrement operators, assignment statements, or function calls in combination with preprocessor macros. Consider: for( i = 0; i < 10; ) printf( "%d squared = %dn, i, SQUARE( i++ ) );  Preprocessor macros can take multiple arguments: #define A_MOD_B(a,b) ( (a) % (b) )  Preprocessor macros can also make use of previously defined macros #define MAX(a,b) ( (a) > (b) ? (a) : (b) ) #define MAX3(a,b,c) ( ((a) > (b)) ? MAX((a),(c)) : MAX((b),(c)) ) // or #define MAX3(a,b,c) ( MAX((a), MAX((b),(c)) )  Preprocessor macros can span multiple lines only if the end of line is explicitly escaped: #define MIN(a,b) ( (a) < (b) ? (a) : (b) )  Note that macros do not check the types of their arguments, which can have both good and bad consequences. Predefined Macros  There are a number of macros automatically pre-defined by the compiler, inlcuding the following list. Note that each one begins and ends with TWO underscore characters: o __LINE__ - The line number of the current file being compiled o __FILE__ - The name of the current file being compiled o __DATE__ - The current date o __TIME__ - The current time The #pragma Preprocessor Directive  The #pragma directive is used to give the preprocessor ( and compiler ) specific details on exactly how to compile the program. For example, specific compiler warnings can be ignored, or warning levels changed up or down for different sections of code.  Examples: o #pragma page( ) // Forces a form feed in the listing
  • 8.
    o #pragma warning(disable: 2044 ) // Disables warning number 2044 o #pragma line 100 // Sets the current line number to 100 for listing and reporting purposes. Header Files  A header file is a file with extension .h which contains C function declarations and macro definitions to be shared between several source files. There are two types of header files: the files that the programmer writes and the files that comes with your compiler.  You request to use a header file in your program by including it with the C preprocessing directive #include, like you have seen inclusion of stdio.h header file, which comes along with your compiler.  Including a header file is equal to copying the content of the header file but we do not do it because it will be error-prone and it is not a good idea to copy the content of a header file in the source files, especially if we have multiple source files in a program.  A simple practice in C or C++ programs is that we keep all the constants, macros, system wide global variables, and function prototypes in the header files and include that header file wherever it is required.  Include Operation  The #include directive works by directing the C preprocessor to scan the specified file as input before continuing with the rest of the current source file. The output from the preprocessor contains the output already generated, followed by the output resulting from the included file, followed by the output that comes from the text after the #include directive. For example, if you have a header file header.h as follows –  char *test (void); and a main program called program.c that uses the header file, like this –  int x;  #include "header.h"   int main (void) {  puts (test ());  }
  • 9.
    the compiler willsee the same token stream as it would if program.c read.  int x;  char *test (void);   int main (void) {  puts (test ());  }  Once-Only Headers  If a header file happens to be included twice, the compiler will process its contents twice and it will result in an error. The standard way to prevent this is to enclose the entire real contents of the file in a conditional, like this −  #ifndef HEADER_FILE  #define HEADER_FILE   the entire header file file   #endif  This construct is commonly known as a wrapper #ifndef. When the header is included again, the conditional will be false, because HEADER_FILE is defined. The preprocessor will skip over the entire contents of the file, and the compiler will not see it twice.  Computed Includes  Sometimes it is necessary to select one of the several different header files to be included into your program. For instance, they might specify configuration parameters to be used on different sorts of operating systems. You could do this with a series of conditionals as follows −  #if SYSTEM_1  # include "system_1.h"  #elif SYSTEM_2  # include "system_2.h"  #elif SYSTEM_3  ...  #endif