Home | Department of Computer Science



clarkcs3843syllabuslecture notesprogramming assignmentshomeworkset up?PreprocessorThe C preprocessor is used to extend the notation of C. Some capabilities:#include is used to include C code from include (.h) files#define is used to define constants or expandable macros#if is used for conditional logic within the preprocessor.The C preprocessor runs automatically when you compile. If you want to see what it produced, you can trygcc -E my.corcpp my.cSometimes, the output from the C preprocess is difficult to read. You might want to redirect the output to sed and indent commands to improve it.gcc -E my.c | sed '/^\#/d' | indent -st -i4 > my_x.cYou have already seen the #include preprocessor statement which has two forms:#include <filename>#include "filename"Note that the compiler supports a -I option for you to provide a path to search for include files.You have also seen #define for defining constants (i.e., simple macros).#define ERR_INPUT_FILENAME "Input filename is invalid, found "#defineWe have already used the form of #define which allows us to name a constant. C considers those to be simple macros or macros without arguments. #define PI 3.14159#define SSN_SIZE 9#define SSN_PLUS_1_SIZE SSN_SIZE + 1 #define macros with arguments#define can also be used to define macros having arguments. This can be used to extend the capabilities of C. C doesn't support an exponentiation operator. It could be convenient to create a SQUARE macro having arguments. In the definition, it may be useful to surround the referenced arguments with parentheses to avoid some problems.Define a macro to square something#define SQUARE(X) X*X// careful this can cause problems// Example 1 - computing area of a circledCircleArea = PI * SQUARE(dRadius);// that would expand todCircleArea = 3.14159 * dRadius * dRadius;// Example 2dCircleArea = PI * SQUARE(dRadius+1);//expands todCircleArea = 3.14159 * dRadius+1 * dRadius+1;How do we fix that?#define SQUARE(X) (X)*(X)// careful this can cause problems//Example 2 would expand todCircleArea = 3.14159 * (dRadius+1) * (dRadius+1);//Example 3 - 1 divided by the square of dLambdadResult = 1 / SQUARE(dLambda);//expands todResult = 1 / (dLambda)*(dLambda);How de we fix that?#define SQUARE(X) ((X)*(X))// much better// Example 3 would now expand todResult = 1 / ((dLambda)*(dLamda));Warning! When defining a macro having arguments, make certain you do not put a space after the macro's name. It will consider that a definition of a constant macro (see SSN_PLUS_1_SIZE above) which doesn't have arguments. The resulting compilation errors are typically difficult to understand.#define SQUARE (X) ((X)*(X))This would not create the macro SQUARE with X as its argument; instead, it creates a constant macro square (without arguments) with its value being (X) ((X)*(X)).One of the more popular uses of #define macros having arguments is to reduce coding for error handling and provide extra diagnostics. If a macro's definition is fairly long, lines can be continued by ending them with a backslash.The following predefined macros can help with diagnostics:__FILE__expands the name of the current C source file__LINE__expands to the current line numberSuppose you wanted to know where an error was found when showing error diagnostics.#define ERR_EXIT(MSG,INFO) {\printf("ERROR: %s %s\n\tEncountered at line %d in file %s\n" \ , MSG, INFO\ , __LINE__\ , __FILE__);\exit(1); }…if (pszFileName == NULL) ERR_EXIT("Missing -i switch", "");// Would expand to (without a compiler issue)if (pszFileName == NULL){printf(ERROR: %s %s\n\tEncountered at line %d in file %s\n" ,"Missing -i switch", "" , 36 ,"full path/myprogram.c");exit(1);};Note: that definition has a problem when used in some C code. #if, #ifndef, and #ifdefThe C preprocessor supports conditionals that are resolved during preprocessor execution. The conditionals resemble C conditionals. Reasons for conditionals:The same declarations of variables, typedefs or prototypes may be needed in several include files. The preprocessor conditional can help avoid errors associated with redefining those.A program may have debug information that was very useful during development and testing, but will impact performance when a program is moved to production. The preprocessor conditional can be used to leave out that debug information from the generated executable.A program may need to use different code depending on particulars of a particular machine, operating system or compiler. The preprocessor conditional can help provide code that can run anywhere, but has those kind of particulars.Each of those C preprocessor if statements must be ended by an #endif. Those also support an optional #else.// For reason #1, we typically code this for include file xyz.h#ifndef XYZ_H#define XYZ_Htypedef struct xyz{ blah blah blah} xyz;#endifKeeping debug statements in your codeSome debug capabilities are too useful to simply delete from your code; however, you don't want them to impact execution for production code. This can be solved by using #ifdef DEBUG_ON. Note that we could have called it any name (e.g., SPURS).#define DEBUG_ON…int main(…){ //some code#ifdef DEBUG_ON fprintf(stderr, "debug: at %d, myVar is %s\n" , __LINE__ , myVar);#endif // some more code#ifdef DEBUG_ON fprintf(stderr, "debug: at %d myOther is %s\n" , __LINE__ , myOther);#endif It might be useful to have a macro which prints debug information to standard error only when DEBUG_ON is defined. In this example, we have coded three DEBUG macros:DEBUG(S)prints information about a string variable SDEBUGD(S)prints information about a double variable SDEBUGL(S)prints information about a long variableIf we executed DEBUG(szSSN) it would print a message like the following:debug: at line 36, szSSN is ''#define DEBUG_ON#ifndef DEBUG_ON// define the DEBUG macros as null values (i.e. doesn't do anything)#define DEBUG(S) #define DEBUGD(S)#define DEBUGL(S)#else#define DEBUG(S) fprintf(stderr, "debug: at line %d, %s is '%s'\n" \ , __LINE__\ , #S\ , S)#define DEBUGD(S) fprintf(stderr, "debug: at line %d, %s is %10.2lf\n" \ , __LINE__\ , #S\ , S)#define DEBUGL(S) fprintf(stderr, "debug: at line %d, %s is %ld\n" \ , __LINE__\ , #S\ , S)#endif Recognizing different machines or OSMicrosoft compilers define the constants _WIN32 and _WIN64. If those are undefined, we aren't running compiling on either 32 bit or 64 bit Windows. // partial timestamp.h include file#include <time.h>// If running on Microsoft Windows, redefine gettimeofday to one// that invokes ms windows APIs.#if defined(_WIN32) || defined(_WIN64)#define gettimeofday(tv,tz) ms_gettimeofday(tv,tz)#include <WinSock2.h>struct timezone{ long tz_minuteswest; // minutes W of Greenwich int tz_dsttime; // type of daylight savings correction};int ms_gettimeofday(struct timeval *ptv, struct timezone *ptz);#else// include the standard Unix include file for timestamps#include <sys/time.h>#endifEarlier, we said that the ERR_EXIT macro has a problem. What is it? What would cause a compilation error in the expansion?#define ERR_EXIT(MSG,INFO) {\printf("ERROR: %s %s\n\tEncountered at line %d in file %s\n" \ , MSG, INFO\ , __LINE__\ , __FILE__);\exit(1); }…if (rc!=0) ERR_EXIT("Unknown problem for ", pszXYZ);else migrate(pszXYZ);// Would expand toif (rc!=0){fprintf(stderr,"ERROR: %s %s\n\tEncountered at line %d in file %s\n" ,"Unknown problem for ", pszXYZ , 36 ,"full path/myprogram.c");exit(1);};else migrate(pszXYZ);ERR_EXIT expands to multiple statements which must be surrounded by {}, but it is more natural to reference ERR_EXIT followed by a semicolon which causes the expansion to end with "};". One solution around this problem is to use a do { … } while statement which must end with a semicolon.#define ERR_EXIT(MSG,INFO) do {\ fprintf(stderr,"ERROR: %s %s\n\tEncountered at line %d in file %s\n" \ , MSG, INFO\ , __LINE__\ , __FILE__);\ exit(1); } while (0)if (rc!=0) ERR_EXIT("Unknown problem for ", pszXYZ);else migrate(pszXYZ);// Would expand toif (rc!=0)do{fprintf(stderr,"ERROR: %s %s\n\tEncountered at line %d in file %s\n" ,"Unknown problem for ", pszXYZ , 36 ,"full path/myprogram.c");exit(1);} while(0);else migrate(pszXYZ);Warning: as with other programming tools, macros can be dangerous. It may be more difficult to understand a problem which was caused by macro expansion than straight coding. Do NOT create tricky macros. ................
................

In order to avoid copyright disputes, this page is only a partial summary.

Google Online Preview   Download