------------------------------------------------------------------------------- What macros are pre-defined Gcc at least man probably other compilers will list the predefined macros which given a -v option EG: gcc -v hello_world.c Reading specs from /usr/lib/gcc-lib/i486-linux/egcs-2.91.66/specs gcc version egcs-2.91.66 19990314/Linux (egcs-1.1.2 release) /usr/lib/gcc-lib/i486-linux/egcs-2.91.66/cpp -lang-c -v -undef -D__GNUC__=2 -D__GNUC_MINOR__=91 -D__ELF__ -Dunix -Di386 -D__i386__ -Dlinux -D__ELF__ -D__unix__ -D__i386__ -D__i386__ -D__linux__ -D__unix -D__i386 -D__linux -Asystem(posix) -Asystem(unix) -Acpu(i386) -Amachine(i386) -Di386 -D__i386 -D__i386__ -D__tune_i486__ ------------------------------------------------------------------------------- Concatation Macro This marco is used to concatate two identifiers together into one identifier for the compler. This macro is normally defined in ansi C include files: memvar.h. #ifndef CAT # undef IDENT # define IDENT(x) x # ifdef __STDC__ # define CAT(a,b) a##b # else # define CAT(a,b) IDENT(a)b # endif #endif ------------------------------------------------------------------------------- BSD to SysV Marco converters For System V machine /* SysV memcpy for bcopy (note argument positions) */ #define bcopy(s,d,n) memcpy(d,s,n) #define bzero(p,n) memset(p,'\0',n) #define index(p,c) strchr(p,c) For BSD #define memcpy(d,s,n) bcopy(s,d,n) ------------------------------------------------------------------------------- Tests on string defines Cpp normall can not compare string defines. However through the use of some carefully trickery it can be done EG: #define anthony 1 ! any number other than 0 would work here #define jonh 2 ! any different number here #if USER == anthony # define AUTHOR "Anthony Thyssen" #elif USER == john # define AUTHOR "John Doe" #endif #undef anthony ! don't forget or other problems may occur #undef john Idea (for X resources) by: Johnny Tolliver jxt@ca12.cad.ornl.gov ------------------------------------------------------------------------------- Rules for writing C macros. * never put a final `;' on the end of a macro -- let the caller provide this. * Bracket all arguments and the total macro expression. This avoids Bad Case: #define multiply(a,b) a * b multiply(5,2+10) --> 5 * 2 + 10 --> 20 Corrected: #define multiply(a,b) ( (a) * (b) ) multiply(5,2+10) --> ( (5)*(2+10) ) --> 60 * If possible only use a argument once to avoid expression duplication and thus duplication of side effects, such as pre/post increments. Example: #define abs(x) ( (x)>0 ? (x) : -(x) ) abs( i++ ); /* i will be double incremented by the macro! */ To stop this assign the expression argument given to a temporary variable and thus only evaluating that expression only once. EG: int tmp; /* temporary variable for macro */ #define assign(ary,int) ( tmp = (int), ary[tmp] = tmp ) assign(my_array, i++); /* i is not double incremented */ * Two types of macro are ingeneral use. Expression and Proceedural. Expression macros, are numerical expressions that ``return'' a result into the code where they are placed. These macros are the most common type of macro in use and is characterized by the use of brackets (...). Problems with expression macros:- * No looping or recursion. * No variable declarations * can be very obtusicated Proceedural macros, allow the use of loops and variable declarations and usually consist of a brace block {...} to group all the statements, This is to avoid problems with looping statements and within if constructs. However C syntax does NOT permit a `;' to be placed after the close brace and an else as this results in two statements between the if and the else statement. For example :- if (...) {...} ; else This makes using just braces to enclose the block a problem. The solution is to make the brace block a do loop which is executed only once. Aluturnatively a if statment though a missing semi-colon could be a problem in this case. General solutions to the brace-block problem. #define macro(x) do { statements; } while (0) /* preferend */ #define macro(x) if (1) { statements; } else Problems with proceedure macros:- * Brace-block problem requires extra code which is removed by the compiler (optimization) but lint will complain about. * No value return (void macro proceedures only) * No recursion though looping is possible. The General concenses is to avoid proceedural macros whenever possible using expressional macros instead. The following is a conversion table between the two marco types. Proceedures use Expression macros use do {...} while(0) (...) ; , if (...) ... ( (...) && (...) ) if (!(...)) ... ( (...) || (...) ) if(...) ... else ... ( ... ? ... : ... ) Example: #define strdup(new,old) (new) = malloc(strlen(old)+1); \ strcpy((new),(old)) Proceedural: # define strdup(new,old) do { \ (new) = malloc(strlen(old)+1); strcpy((new),(old)) \ } while(0) /* no trailing ; */ Espressional: #define strdup(new,old) \ ( (new) = strcpy( malloc(strlen(old)+1), (old) ) ) Remember that just incasing the macro in {...} gives a `;' following the braced block which is illegal in many cases (like if). ------------------------------------------------------------------------------- Variable Number of Arguments in a macro The best `trick' is to define a macro with a single set of parentheses and call it with a double set of parentheses, which appear to the preprocessor to indicate a single argument: #define DEBUG(args) (printf("DEBUG: "), printf args) if(n != 0) DEBUG(("n is %d\n", n)); It is often better to use a bona-fide function, which can take a variable number of arguments in a well-defined way. -------------------------------------------------------------------------------