------------------------------------------------------------------------------- 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__ ------------------------------------------------------------------------------- BSD to SysV Macro 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) ------------------------------------------------------------------------------- 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. echo ' #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 CAT(pre,fix) ' | cpp -P - Does not work for non-identifiers, such as paths! EG this fails #define HOME /home/user CAT(prefix,HOME) ------------------------------------------------------------------------------- Stringify Macro echo ' #define STR(s) #s STR(My Name) ' | cpp -P - But the above will fail if you use a define so you need to expand the define before you stringify it echo ' #define STR_AUX(s) #s #define STR(s) STR_AUX(s) STR(HOME) ' | cpp -P -DHOME="$HOME" - ------------------------------------------------------------------------------- Path macros are a pain to use echo ' HOME/this_works :HOME/this_works: "HOME/no_expansion" prefix/HOME/space_gets_prepended file://localhost/HOME/this_is_worse ' | cpp -P -DHOME="$HOME" - Warning mcpp (used by xrdb) appends a space in ALL cases! NOTE you can not use a macro directly quotes making it fail for includes or use it as part of a sting in includes. But includes can take a whole macro defintion! echo INCLUDED > ~/t echo '#include "HOME/t"' | cpp -P -DHOME="$HOME" - # fail echo '#include ' | cpp -P -DHOME="$HOME" - # fail echo ' #define INCLUDE #include INCLUDE ' | cpp -P -DHOME="$HOME" - # works, <> is equivelent for a full path Using stringify to generate a quoted include path echo ' #define STR_AUX(s) #s #define STR(s) STR_AUX(s) #define INCLUDE STR( HOME/t ) include INCLUDE #include INCLUDE ' | cpp -P -DHOME="$HOME" - # works ------------------------------------------------------------------------------- Generating quoted URL's from defines How to generate "http://hostname HOME /index.html" with HOME expanded and no extra spaces and quoted echo ' file://hostname #define IDENT(s) s IDENT(file:)//hostname,HOME ' | cpp -P -DHOME="$HOME" - All you get is just file: !!!!! No solution! ------------------------------------------------------------------------------- Tests on string defines Cpp normally cannot 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 john 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 xrdb -DUSER=`whoami` .Xresources 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 */ * Expression Macros... 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 * be careful about argument side effects (like increment) * Proceedural macros... 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. For example (bad)... #define swap(a,b) { int t=a; a=b; b=t; } However C syntax does NOT permit a `;' to be placed after the close brace when an else follows... For example using the above brace macro... if (x