4 ms·
The problem with all this advice is that C lacks so many amenities of modern programming languages (no module system, no opaque types, no automatic memory manag
by rbehrends 10y ago
The problem with all this advice is that C lacks so many amenities of modern programming languages (no module system, no opaque types, no automatic memory management or RAII, no closures, no parametric polymorphism, no subtyping) that working around these limitations is bound to violate some of it.
The same strict rules that you can afford to adhere to in other languages do not work for C: with C, the often delicate balance of tradeoffs can tip either way.
> Do not use a typedef to hide a pointer or avoid writing “struct”.
This really seems to fly in the face of the idea of information hiding, at least when listed as an absolute. The client of a module does not need to know whether (say) a handle is an int or a pointer.
> Do not use macros.
> Never put code into a header. Never use the inline keyword.
This just doesn't strike me as good advice. You're creating potentially costly abstractions. For example:
for (foo_init(&foo); !foo_done(&foo); foo_next(&foo)) {
...
}
Without macros or static inline functions, you're creating overhead. Overhead that other languages with proper module systems can avoid, but not C, so you have to work around it. Sometimes it's not an issue, sometimes this is code that you want to use in a hot loop. By not having low-overhead abstractions, you're encouraging manual inlining or hacking around their lack when writing performance-critical code (and if you aren't writing performance-critical code, why are you using C)?
Macros are also the only alternative that you have in C to compensate for the lack of closures. They aren't closures, and they aren't even good macros, but cover some of the same use cases.
> Do not use fixed size buffers - always calculate how much space you’ll need and allocate it.
This is not exactly wrong, but it only talks about half of the problem. The alternative to fixed size buffers are manual memory management or alloca(). Manual memory management is also error-prone and alloca() can blow up the stack. It's not that people necessarily think that fixed size buffers are good: they're choosing between various pain points. Fixed size buffers with a generous upper limit that is properly enforced can make for a perfectly viable trade-off.
> Keep your build system simple and transparent.
This is a bit vague. What's "simple and transparent"? At some point, you'll have to deal with things like how to figure out dependencies, for example. Preprocessors and code generators are common in C projects, often to reduce common C pain points.