Here are a few notes from the yellow notepad I’ve been using for school over the last six months. This first installment touches on C. Later I’ll add some UNIX programming and C++ notes. Basically these are the things that struck me as I was quickly reading the “refresher” material for my spring class: “Advanced C Programming for UNIX.” After more than a decade with C, I feel I know the core language pretty well; and here are the things that struck me as worth noting.
Is there a portable way to refer precisely to datatypes of a particular size? Yes, in C99 #include <stdint.h>.
Use signed integer types larger than char with getc() or getchar() to accomodate EOF (-1).
A good running average is avg += (x - avg) / n; It reduces the chance of overflow, is fast, and doesn’t require you to keep track of all values.
Each comment collapses to a single blank character during parsing.
Many system names start with an underscore ( “_” ). Avoid creating new identifiers that start that way.
All functions have extern storage, just like variables defined outside of a function.
Use volatile when it’s possible that the variable’s value will change from outside the normal flow of control. Technically this prevents compiler and processor instruction reordering optimizations around the use of the variable.
The register storage class is for small, fast-changing variables like loop indices (not for bigger things like arrays). And you can’t do &variable for register-declared storage.
Array names are const pointers, so an array name is not a valid l-value.
It’s not possible to take an address of a literal value, like 3.14 or "I am the very model of a modern major general.". So . . .
Because C-strings are either arrays (char s) or pointers to memory areas (char *s), it’s illegal to reassign a value to a string variable directly (e.g., s = "new string"; /* won't compile */).
When passing multidimensional arrays to a function, the function’s argument list must give the size of all but the slowest changing dimension.
Function pointers: int (*f)(int, double) is the same as int f(int, double). The parentheses are necessary to ensure the * binds to f and not int. To use the function pointer f either of these is acceptable: (*f)(37, 3.14) or f(37, 3.14). (This is “declaration follows usage.”)
const int *p is a pointer to a constant int.
int const *p is a constant pointer to an int.
“LP64″ scheme means long ints and pointers are 64-bit values.
Some compilers use precompiled headers to speed up compilation. This can make the inclusion order of header files significant. Also, some compilers (like Xcode) use “prefix headers,” which are always included in a project.
Defining NDEBUG turns the assert() macro into a no-op.