• One can trigger gdb breakpoints from code by inserting: asm("int $0x3\n");
  • Beware of signed/unsigned integer comparisons: -Wsign-compare is a very useful option to enable so as to pin point possible issues in signed comparison. For details on this issue see Ian Lance Taylor's info. For a concrete example, see this coreutils bug fix identified with -Wsign-compare
  • Beware of signed integer overflow handling: Later gcc versions may ignore code that assumes signed integers will wrap around on overflow. Even later gcc versions added the -Wstrict-overflow option (which -Wall includes) to warn when it was doing this, so one can find and change problematic code to more portable contructs. You can search for "OFF_T_MAX" in the new coreutils truncate utility, to see how I handled overflow for various integer operations. See also Integer Overflow considerations.
  • One can check gcc supported options and code using: echo "void f(int i) {i++;int j;}" | ${CC:-gcc} -xc -c -o /dev/null - 2>/dev/null && echo c99 Note one can instruct gcc to act like a c89 (ansi c) compiler for testing like: echo "void f(int i) {i++;int j;}" | gcc -std=c89 -pedantic -Werror -xc -c -o /dev/null - 2>/dev/null || echo c89 See also the Autoconf AC_PROG_CC and AC_PROG_CC_STDC etc. macros.
  • The printf man page is more like a specification than a quick reference. So I created a quick reference for the format specifications, and some more detailed notes on C99 integer types. Note also, the latest linux man pages for the kernel syscall and glibc function interfaces are browsable online as of Dec 2007.
  • A common requirement is to get the length of an array at compile time, for which I find the following macro (which is analogous to sizeof) useful: #define lengthof(x) (sizeof(x)/sizeof(x[0])) Also note that C99 supports variable length arrays.
  • It can be quite confusing sometimes to know exactly what is #defined in your program, and this is especially true for glibc's "feature" macros. These macros are documented (info libc "feature test macros"), but it's much easier to see what's defined directly using "cpp -dD" like: $ echo "#include <features.h>" | cpp -dN | grep "#define __USE_" #define __USE_ANSI #define __USE_POSIX #define __USE_POSIX2 #define __USE_POSIX199309 #define __USE_POSIX199506 #define __USE_MISC #define __USE_BSD #define __USE_SVID $ echo "#include <features.h>" | cpp -dN -std=c99 | grep "#define __USE_" #define __USE_ANSI #define __USE_ISOC99 Also to see all the predefined macros one can do: $ cpp -dM /dev/null Note also for compiler specific macros you can do: $ gcc -E -dM - < /dev/null See also my strerror script which uses the same technique. See also this list of predefined macros for various systems.
  • Determining the optimum gcc settings for a particular CPU can be challenging. To that end I created a script that gives the answer automatically for 32 bit x86 processors on linux at least.
  • Starting with GCC 3.0 one can give branch prediction hints to the compiler. This can help immensely for performance critical code. Note one should only use these hints where absolutely necessary because they make the code more complicated to read/maintain. For details search for builtin_expect in `info gcc` #if __GNUC__ < 3 #define __builtin_expect(foo,bar) (foo) #define expect(foo,bar) (foo) #else #define expect(foo,bar) __builtin_expect((long)(foo),bar) #endif /* idea for these macros taken from Linux kernel */ /* Note tests for NULL (!something) don't need an unlikely as gcc does that by default itself */ #define __likely(foo) expect((foo),1) #define __unlikely(foo) expect((foo),0) An example use is: for(;;) { //hot loop ret = op1(); if (__unlikely(ret == error)) { //handle error } ... }
  • Setting CPU affinity for a process/thread on linux requires calling the following code in userspace: (Note the 2.4 vanilla kernels require a simple patch to support this) /* As can be seen here the sched_setaffinity() interface has changed 3 times: rh9 = glibc-2.3.2 = int sched_setaffinity(__pid_t __pid, unsigned int __len, unsigned long int *__mask); fc1 = glibc-2.3.3 = int sched_setaffinity(__pid_t __pid, __const cpu_set_t *__mask); fc2 = glibc-cvs = int sched_setaffinity(__pid_t __pid, size_t __cpusetsize, __const cpu_set_t *__cpuset); therefore call the syscall directly. */ #undef __NR_sched_setaffinity #define __NR_sched_setaffinity 241 //2.4 specific #include <unistd.h> #include <linux/unistd.h> _syscall3(int, sched_setaffinity, pid_t, pid, unsigned int, len, unsigned long *, user_mask_ptr) //The above equivalent to: int sched_setaffinity(pid_t pid, unsigned int len, unsigned long *mask); //This function sets affinity to a particular CPU. Pass in 0,1,2,3,... static void set_affinity(unsigned long cpu) { cpu = (1 << cpu); sched_setaffinity(0, sizeof(cpu), &cpu); } See also the plpa lib for abstracting away from the 2 obsolete interfaces.
  • There are 2 methods of supporting 64 bit files on linux (glibc). I.E. supporting large files > 2GiB. 1. You can do it explicitly in the source by defining _LARGEFILE64_SOURCE and then calling open(,O_LARGEFILE), stat64(), lseek64() etc. 2. You can also get everything working implicitly by just defining _FILE_OFFSET_BITS=64 and using the standard open(), stat(), lseek() etc. calls.
  • The following options to gcc can be used to get more info about a specified c file. -E #preprocessor output to stdout -S #assembly to cfile.s -MM #make dependencies to stdout -aux-info file #prototypes to file -H #header files used to stdout
  • C++ "Get/Set" methods can use function overloading to expose just one name, which makes things much cleaner. For e.g: class myclass { int priv_int; public: int Priv_int(void) {return priv_int}; void Priv_int(int t) {priv_int = t}; };
  • sizeof(type) has more coupling (bad) than sizeof(variable). For e.g.: int var; memset(&var,0,sizeof(int)); /* bad */ memset(&var,0,sizeof(var)); /* good */
  • Here are my indent settings: -kr -l78 -lc78 -lps -i4 -br -bbo -bad -bap -cs -nbc -nhnl -nss Some people also like to add: -pcs -psl
  • const and volatile declarations are confusing, they modify the nearest item (on their left), so... 1. const int* p_ci /* Pointer to const int */ 2. int const* p_ci /* Pointer to const int */ 3. int *const cp_i /* const pointer to int */ Note 2. gives a parse error in cdecl 2.5
  • 071 is an Octal number in C (leading zero) 71 is an decimal number in C (no leading zero)
  • #include directive forms: #include "file.h" //or "dirs/file.h" #include <file.h> //or <dirs/file.h> #include "/usr/include/file.h" The "" relative form, instructs the preprocessor to look for include files in the same directory of the file that contains the #include statement (the parent file), and then in the directories of whatever files that include (#include) that file (grandparent files). If no file is found the preprocessor does as if <> were used. For the if <> (relative) form the preprocessor searches along the path specified by the compiler include path, which could be specified using an INCLUDE environment variable or -I options etc. The last absolute address form, doesn't do any path searching. It just looks for the file @ the specified path.
  • The C++ equivalent of: pos = sprintf(buff , "%3d %5ld \n",i,lng); is: ostringstream Stm; //Note strstream is old & non standard. string Str; Stm << setw(3) << i << " " << setw(5) << lng; Str = Stm.str();
  • /* Example program showing how to parse comma seperated strings. I've seen many times where people write their own (usually flawed) code to parse strings like this. */ #include <stdio.h> int main(void) { char str1[2]; char str2[2]; char str3[2]; char str4[2]; char* t="1,2,3,4"; sscanf(t, "%[^,],%[^,],%[^,],%[^,]", str1, str2, str3, str4); printf("str1=[%s], str2=[%s], str3=[%s], str4=[%s]\n", str1, str2, str3, str4); }
  • /* The following will not work generally as if linux is defined as one for e.g., then the following will try and #include <net-snmp/system/1.h> */ #define INC <stdio.h> #define INC2 <net-snmp/system/linux.h> #include INC #include INC2 int main(void) { printf("Hello world\n"); return 1; }
© Oct 16 2006