As far as I’m concerned, there’s only one way to write C-like code. First of all, you must select sane whitespace defaults in your editor. Here’s the one true way to configure Emacs.
(setq default-tab-width 8) (defun one-true-style () (c-set-style "bsd") (setq tab-width 8) (setq c-basic-offset 4) (setq indent-tabs-mode t)) (add-hook 'c-mode-hook 'one-true-style) (add-hook 'objc-mode-hook 'one-true-style) (add-hook 'c++-mode-hook 'one-true-style) (add-hook 'php-mode-hook 'one-true-style)
Other rules of thumb, most of which I picked up from Adobe:
- always use curly braces for if/else/for/while, even if you don’t need them
- every brace goes on a line by itself
- the * is adjacent to the variable name, not the typename
- no extra whitespace inside parens
- always use one space after comma to separate function args
- prefer &foo[i] over foo + i
- prefer foo == NULL over !foo
Here’s a concrete example:
#include <stdio.h> #include <unistd.h> #include <errno.h> int quux(char *foo, size_t len, const char *bar, int flags) { int i, j; char buf[BUFSIZ], *cp; if (foo == NULL) { errno = EFAULT; return -1; } for (i = 0; i < len; i++) { for (j = 0; j < BUFSIZ; j++) { /* something here */ } } return 0; }
I’ve never been a big fan of Hungarian notation for variable prefixes. I do think prefixes have a place; within a library all function names need to be prefixed with some short (3-6 char) name so it’s easy to see which APIs you’re using. I don’t see the point of decorating my variable names like pchFoo. Maybe because it’s too distracting to be constantly thinking of the Pacific Coast Highway.
So I’m not the only one…
I’m with you on rule #1. I think half of my commits are fixing that peve in other peoples code.
Hey, a sane coding style
I whole-heartedly concur with all that is good an geeky. In my own code, I tend to also add an…
what about:
NULL == foo
instead to decrease the chance of that nasty assignment bug.
Anyway, that’s what I do.
My opinion:
–always use curly braces for if/else/for/while, even if you don’t need them
Wrong, adds worthless clutter.
–every brace goes on a line by itself
Wrong, wastes space.
–the * is adjacent to the variable name, not the typename
Wrong, see the sacred words of St. Bjarne.
–no extra whitespace inside parens
OK
–always use one space after comma to separate function args
OK
–prefer &foo[i] over foo + i
Depends on context, no hard and fast rule.
–prefer foo == NULL over !foo
Wrong on two counts: depends on context, and in any case, no sane C++ programmer writes NULL in the first place. The correct spelling for a null pointer is 0.
How do you format if-else statements?
As for ‘NULL == foo’, that makes me want to scream. Do you think ‘if foo is null’ or do you think ‘if null is foo’?
If the former, then that’s what you should write. If the latter, then your mind is very strange indeed.
I’ve heard rumours of this alleged ‘nasty assignment bug’, but my rule for that is just to not write the wrong thing. I don’t expect I’ve made that mistake more than a couple of times in 15 to 20 years of writing C; my brain just isn’t wired that way.
The damage to readability (‘if null is foo’) far outweighs the risk of me confusing assignation and equality.
Hear! Hear! In this era of personal terabyte drives and multi-gig partitions, it’s absolutely scandalous to wastefully use an extra ^J and a few ^I just for this highly dubious “readability” whine I hear from so many people. By Goodness! What will the Lines of Code counters think?
Come to think of it, variables and functions longer than four letters should be banned too! Horrid waste of precious hard drive space.
> –the * is adjacent to the variable name, not the typename
> Wrong, see the sacred words of St. Bjarne.
St. Bjarne is wrong. Derived-type tokens — *, [] and () — are properly bound to the variable name and not the basic type.
1) doing otherwise leads to “surprises” like:
int* i, j; // one a ptr, one not a ptr
2) this doesn’t scale when the types get more complicated
int (*i)(); // i is ptr to fcn returning int
“Orthogonality” is important to readability
http://www.dsmit.com/lisp/whitespace.el
http://checkstyle.sourceforge.net/
http://www.gnu.org/software/indent/
http://www.uvm.edu/~ashawley/c/indent/
http://astyle.sourceforge.net/
8 space tabs, huh? You must either have a larger monitor than I do or use a higher resolution. (Actually, both are probably true.)
If I use anything large than 4 space tabs, I start scrolling off into the right hand side of the monitor…
I started out using this style (although only 3 spaces for the tabs), but prolonged exposure (perhaps over-exposure 😉 to unix code has lead me to use K&R style braces for code blocks other than the function body itself.
I now use 4 spaces for tabs, but that is largely due to the PHP coding standards. Anything larger leads to horizontal scrolling or excessive line wrapping. Or did. Now we have stupidly high resolution wide screen displays, this isn’t such a problem anymore.
you lost me at “only one way”..
I’m slowing being turning to a no-tabs-ever person.. I used to be tabs-for-indentation-at-start-of-line-ONLY, because then it does not matter what tab widths people use (and I used 4). But it seems to be common practice among C coders to mix tabs and spaces for indentation, so I’m being forced to “:set ts=8”, which is not a practical indentation width, so “:set expandtab” it is for me, I guess.
“NULL == foo” and the alleged “nasty assignment bug” —
This is the 21st century, and we have compilers that warn us if we write “if (foo = NULL)”. I’m not going to suffer through the pain of reading “NULL == foo” all the time just because you don’t know how to switch on the relevant warnings.
“8 space tabs, huh? You must either have a larger monitor than I do or use a higher resolution” —
Or it might be that you aren’t aware of the distinction between physical tabs and what you use to indent code. They don’t have to be the same — see for example “c-basic-offset” in Michael’s post, and http://www.jwz.org/doc/tabs-vs-spaces.html .
Coding Conventions
I stumbled onto this post on coding conventions within hours of reformatting about 20 of PulpFiction’s implementation files to suit my code markup. My style closely mirrors that espoused at the page above, but as I looked through our code,…
I dislike the “NULL == foo” idiom for the main reason that it encourages sloppiness in if and while statements. “Since I always do constant == varname, I’m safe from the assignment error”, but then if you do “varname = varname” in your if, your mind isn’t paying attention to the number of equal signs. So I always use varname == constant since it reads more naturally, and I always make myself aware of the operator used in if statements.
I’m with you except for #2. I *much* prefer a cuddled else and opening braces on the same line as the keyword they refer to.
There seems to be some confusion about c-basic-offset and tab-width. To clarify:
Four spaces should be used as the unit of indentation. The exact construction of the indentation (spaces vs. tabs) can vary line-by-line. Tabs must be set exactly every 8 spaces (not 4).
Borrowed from Sun’s Java coding convetions.
1) doing otherwise leads to “surprises” like:
int* i, j; // one a ptr, one not a ptr
Never seems to happen to me. Not that I’m claiming any great expertise; it’s merely the case that if you’ve got any sense, you evolve a style that protects against mistakes; and if you don’t make a particular mistake, there’s no need to compensate for it in your programming style.
I think I don’t suffer from that particular problem, partly because I tend to not declare variables until I’m ready to give them a value (this is of course not possible, in any practical sense, in C, but is to my mind the preferred style in C++) and then ‘one name per declaration’ seems to be my style. That is, I think, definitely true of pointers: I don’t have excess pointer variables hanging around waiting to be used.
I used to be a proponent of the K&R style, but it looks way too weird for references:
char *&string = bar;
K&R style tempts you to think that ‘*&string’ is a char, where actually ‘*string’ is a char. The notation
char*& string = bar;
seems to conver the notion that ‘string’ has a reference type much more readily – somehow there’s no confusion between ‘address of’ and ‘ref’ when you write that. (Alternatively, it might just be that all the C++ literature uses this format, so it is simply familiar).
**2**