C code (violence)
- The shorter the code, the better. Code is read more often than is written.
- If you can avoid writing code, avoid it.
- Keep it as simple as possible, but not too much. Again, read vs write.
- Read the code. In case of a retch, take a few deep breaths. Continue.
- If there are no comments, it either means the code IS simple, or the code is impossible to understand unless you read a spec. See the top of a file to check if that’s the case.
- Do not put a copy of your license on top of every file. This is awkward.
- Use
/* */
-style comments instead of C++ style. Use//
to comment out parts of code for a quick test. - Put a link to a spec on top if the code implements it. For god’s sake, compiler can’t read and doesn’t care about your spec copy-pasted into the source code. If your code really needs a copy-pasted spec, it sucks.
- Prefer “magic” numbers with in-place comments (over a stupid enum somewhere) if your code deals with parsing of some complex format. It will be easier to debug such code while looking at the data it tries to parse.
- Try writing self-contained code. It should be easy to use and test it separately.
- Function name and ALL its arguments must start from a new line, ALWAYS just one
line. It should be possible to find its definition with
grep ^function *.c
. Return type should be on the line before. - Function prototype ALWAYS takes a SINGLE line, so
grep function *.h
outputs the whole prototype. If it’s too long, you have a different problem. - While it might look really stupid, prepend each function prototype in the header
with
extern
keyword if it’s gonna be used in a new code, i.e. if it’s “public” in some way. It’s easy to see what global variables and functions the header is exporting then, by simply invokinggrep ^extern file.h
. Private/internal function prototype can still be written withoutextern
, so that it won’t show up in the output. - Function should return -1 in case of error, 0 in case of success. Not -2, or -3
unless you declare it in an
enum
to handle specific errors differently (try to avoid this need). - Do not expect functions to return -1 in case of error. Either use
== 0
,!= 0
or< 0
. - Always compare to
nil
/NULL
explicitly. - Learn C operator precedence. Do not overuse parentheses.
- No manual inlining, compiler should do it.
- No
#ifdefs
/#endifs
, code should be self-contained. Consider a separate file with initialization function instead, or a platform-specific implementation, depending on the case. - No
#include
in headers. - No
#ifdef
/#endif
in headers. Include the headers once. See the one above. - Separate
typedef
from actualstruct
andenum
, put it at the top of a file. It’s easy to both grep it and read it then. Seegrep ^typedef file.h
. - Use
enum
instead of#define
if possible. - No 80-column limit, although try to make it as short as easily readable.
- Initialize a variable near the place it’s gonna be used, not at its declaration.
- Do not use
memcpy
unless you absolutely sure. Just usememmove
. - Never ever use
strcpy
, even if you KNOW it fits. - Never ever use
sprintf
, even if you KNOW it fits. - Never ever use
alloca
. - Do not expect the stack to grow.
- Do not expect data to fit in a stack-allocated buffer. Use
malloc
/free
if unsure. - If you have defined
main
function and there issetlocale
on the target OS, callsetlocale(LC_ALL, "C")
there. - Expect a crash on any unaligned access.
- Do not (over)use
const
. - Learn
valgrind
. Use it more often. - Before printing/logging a debug message consider its value. Only important information should be seen. Completely empty output is the best of all.
- Prefer
stderr
over any kind of logging. - Do not make assumptions.
- xkcd is always wrong.
Last update: June 06, 2021 08:58AM