# tips-c -- tips on C programming # $Id$ # Carlos Duarte , 000126 Tricks ------ . toggling states wanted: toggle a=0 a=1 a=0 a=1 for a unknown number of times a = 0 for (...) { a = !a } for (...) { a ^= 1 } for (...) { a++; } a &= 1 this one is OK if `a' isn't needed inside the loop . #defines that act as procedures wanted: a macro that can be safely included anywhere in code #define x() do { ... } while (0) works for multiple statments #define x() switch (0) default: ... works for one statment only, ex: #define PUTCHAR(c) \ switch (putchar(c)) \ case EOF: fprintf(stderr, "putchar failed"), exit(1) ... PUTCHAR(c); #define x() if (0) {} else ... works for one statment also, and might generate warnings if used on a non embraced if #define PUTCHAR(c) if (putchar(c)!=EOF) {} else \ fprintf(stderr, "putchar failed"), exit(1) ... PUTCHAR(c); /* ok */ if (cond) PUTCHAR(c); /* ok, but as of gcc 2.95, a warning is generated */ . optimal conditional code inclusion wanted: compile some code on certain conditions extern char fake_var[2]; ... switch (sizeof(fake_var)) { case sizeof(char[1]): printf("1\n"); break; case sizeof(char[2]): printf("2\n"); break; } one can't declare fake_var as needed to select certain parts of code, on different C files. . fetching data from pointers wanted: get different data types values from a pointer one way, is to declared different data type pointers: char *cp = &any_ptr; printf("char: %c\n", *cp); int *ip = &any_ptr; printf("int: %d\n", *ip); other way, is to use a type cast: printf("char: %c\n", *(char *)&any_ptr); printf("int: %c\n", *(int *)&any_ptr); beware from what can be taken from `any_ptr'. for example: if it isn't word aligned, and we are taking a 4-byte long, it may cause errors, depending on the architecture and implementation Common Mistakes --------------- . pointing to the last char (non '\0') on string usually: t = s+strlen(s)-1 ERROR: if s is empty, t == &s[-1] SOLUTION: t = *s ? s+strlen(s)-1 : s typical case: want to chop the last character while (fgets(buf, sizeof buf, stdin)) { buf[strlen(buf)-1] = '\0'; /** dangerous **/ if (*buf) buf[strlen(buf)-1] = '\0'; /** safer **/ /* but in this case */ char *t; if (*buf && *(t = buf+strlen(buf)-1) == '\n') *t = 0; } . beware with automatic castings: pre declare, or use implicit casts example: #include main() { double x = atof("3.14"); printf("%f\n", x); } -> 1073741824.000000 because atof() isn't pre-declared, it is seen as: x = (double)( (int)atof(..) ) SOLUTION: to pre-declare atof(): #include or: double atof(); in general, always be sure the correct type-casts are being used, either with implicit casts, or with pre-declarations