Prefer C89. Not because I really care about systems that decided to pack up shop before the century turned, but C89 feels more like K&R C and there is very little I need from C99 (yes // is nice). If I want modern shiny stuff, use C++ or Rust.
Principles
Remember why you're using C. Usually it's because you care about performance, portability or simplicity. This is because C let's you control exactly what your program does. To that end avoid writing clever, slow or memory-wasting code that is tied to a specific platform. Be like Spiderman: with great power comes great responsibility.
Style
Spaces and indentation
Some people sware by two (curl) others eight (Kernel) so I am very happy on the fence at four. I use spaces because whatever who cares these days? (it's trivial to convert between them)
Line width
An eighty character limit feels sensible. Like naming things, needing long lines is a sympton of a design problem. However, this is not a hard limit. There may be special cases.
Typedefs
I completely agree with kernel here and do not use these for pointers or structs. Just don't use them for any non-trivial types. There may be special cases for standards conformance (e.g. `pthread_t`) but I'm not writing that kind of code anyway.
Braces
I've never liked putting braces on a newline, it just feels completely pointless.
for (i = 0; i < COUNT; i++) {
action1();
action2();
}
Single statement if, for etc. don't need braces – I like living on the edge.
if (condition)
action();
always_run(); /* your tools should make this obvious! */
Naming
If naming things is hard it's a sympton of bad design. I like being able to pronounce things; in practise this means names that aren't obtuse. The larger the scope the more descriptive the name. Steenberg's convention works quite well, I'm not sure what's it's called but it's a bit like domain name form: `com.mywebsite.subpart` (using `_` instead of course) If this becomes `javax.xml.bind.annotation.adapters` then something has gone horribly wrong!
Functions
Some people like them long, others short. I'm just stealing from kernel because it looks rather sensible:
Functions should be short and sweet, and do just one thing.
In essence, a function can be either wide or long, but not both. Don't try to outsmart the compiler and assume function calls are always slow and bad. But don't just split a function into a list of other functions, that requires a ton of jumping around which is tedious. Always forward declare functions so that you can easily reorder things. Code-gen or preprocessor magic can help automate this.
Gotos
"Go To Considered Harmful". Has anyone actually read this paper? Yes, I did when writing this. It's a little academic and predates C (by four years). My takeaway is that `gotos` are too primitive and that certainly is usually the case, but sometimes in C they are the clearest and cleanest way to achieve some jump. For example for resource cleanup when in loops or branches.
Macros
Treat macros with slightly less scepticism than gotos. Uppercase for constants.
#define CONSTANT 0xFFFF
Macro functions can be lowercase. Use the do-while trick for anything beyond a single statement.
# define func(a, b) \
do { \
... \
} while (0);
Use Arenas
Turns out managing memory isn't that difficult if you have a better model beyond malloc and free.
Better strings
C's null-terminated strings are a common nuisance compared to other languages. These simple structs make dealing with strings 100x better.
struct string {
char *str;
size_t len;
};
struct string_buf {
char *str;
size_t len;
size_t cap;
};
Conditional Compilation
Wherever possible, don’t use preprocessor conditionals (#if, #ifdef) in .c files; doing so makes code harder to read and logic harder to follow. Instead, use such conditionals in a header file defining functions for use in those .c files, providing no-op stub versions in the #else case, and then call those functions unconditionally from .c files.
Where I stole these things from
- https://www.kernel.org/doc/html/v4.10/process/coding-style.html
- https://www.youtube.com/watch%3Fv%3D443UNeGrFoM
Further Reading
- K&R C (2nd Edition - ANSI C)
- The Practice of Programming – K&P
No comments:
Post a Comment