1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222
|
Intro
=====
I'm not a nazi about this (at least *I* don't think I am), but it's
important for a program to have a consistent style throughout. These
rules aren't cast in stone, but if you don't have a *good* reason to
deviate, then don't. Otherwise, I will bitchslap you.
After much deliberation (really, a *lot*), I've decided on a modified
version of k&r style. If you use Emacs, just use k&r as your c-mode
when hacking on Specimen.
Braces
======
I used to follow the strict k&r layout, but after too many hours
wasted furrowing my brow trying to focus on something like...
if (p->play_mode & PATCH_PLAY_LOOP) {
if (p->play_mode & PATCH_PLAY_PINGPONG) {
if ((v->dir > 0) && (v->posi > p->loop_stop)) {
v->posi = p->loop_stop;
v->dir = -1;
} else if ((v->dir < 0) && (v->posi < p->loop_start)) {
v->posi = p->loop_start;
v->dir = 1;
}
} else {
if ((v->dir > 0) && (v->posi > p->loop_stop)) {
v->posi = p->loop_start;
} else if ((v->dir < 0) && (v->posi < p->loop_start)) {
v->posi = p->loop_stop;
}
}
}
...I decided that my A.D.H.D. ass was due for a change. The rule is, all
braces have one line to themselves. Observe the difference in
readability:
if (p->play_mode & PATCH_PLAY_LOOP)
{
if (p->play_mode & PATCH_PLAY_PINGPONG)
{
if ((v->dir > 0) && (v->posi > p->loop_stop))
{
v->posi = p->loop_stop;
v->dir = -1;
}
else if ((v->dir < 0) && (v->posi < p->loop_start))
{
v->posi = p->loop_start;
v->dir = 1;
}
}
else
{
if ((v->dir > 0) && (v->posi > p->loop_stop))
{
v->posi = p->loop_start;
}
else if ((v->dir < 0) && (v->posi < p->loop_start))
{
v->posi = p->loop_stop;
}
}
}
If this style of formatting costs you too much "screen real-estate," I
doubt your system is in any shape to be running Specimen in the first
place.
Naming
======
Types should be written in StudlyCaps, and functions should be
separated_with_underscores(). Variables which need some kind of
multiword distinction should also take the underscore approach. I
like this method because it makes the difference between types and
functions eminently clear, as well as being a good metaphor for the
singularity of types (they're just a thing) and the plurality of
functions (they're a collection of actions).
The first rule of name length is that length should be directly
proportional to scope level. A variable that is local only to a
particular function doesn't need a big name. On the other hand a
function that will be used throughout the program should have a
somewhat lengthier and more descriptive name.
The second rule of name length is that length should be inversely
proportional to frequency of use. If you're going to be using a
variable a whole lot, you'll be well served to keep that name
as short as is reasonable (not uncommonly down to one letter for
function local variables). If you're going to be using a variable
infrequently, it's name should be more descriptive so that you
know what it is being used for when you go back to your code a week
later.
Functions
=========
Global functions should follow this naming convention:
namespace_operation_qualifier(args);
Functions should be focused and to the point. gcc has an inline
keyword, so don't hesitate to break up a function into smaller pieces
if it's starting to get unwieldy. A good indicator is if it gets to
be more than 150 lines, or has more than 10 local variables. Another
indicator is if the indentation level is more than 3, although it is
sometimes desirable to go for a 4th level of indentation rather than
split off into another function.
If your function is conceptually quite simple, than it's ok to break
the above rules. However, if a retard like me won't be able to figure
out what's going on, you should stay well within the limits.
Oh, and if a function doesn't take any parameters, declare it as
foo(void). Otherwise, compilers will assume your using oldskool
function prototype parameter declarations (i.e., none), and that ain't
good.
Pointers
========
When declaring pointer types, this sytnax...
int* foo;
...is preferred over this...
int *foo;
...and this...
int * foo;
The reason is that the first very clearly says "integer pointer" by
smacking the pointer right up there with the type. And anyway,
the asterik is just another type qualifier, and it ought to be
with all the other type qualifiers. You never see anybody write
static const int foo;
The reason? It's stupid. Don't be stupid.
Commenting
==========
From the Linux Kernel Coding Style guidelines:
"Comments are good, but there is also a danger of
over-commenting. Never try to explain how your code works in a
comment: it's much better to write the code so that the working is
obvious, and it's a waste of time to explain badly written code."
"Generally, you want your comments to tell what your code does, not
how. Also, try to avoid putting comments inside a function body: if
the function is so complex that you need to separately comment parts
of it, you should probably go back to chapter 4 for a while. You can
make small comments to note or warn about something particularly
clever (or ugly), but try to avoid excess. Instead, put the comments
at the head of the function, telling people what it does, and possibly
why it does it."
It is vastly more important to comment data structures than it is
functions. I cannot stress this enough. When the data structures are
well understood, everything else falls into place. However, a well
understood function that operates on mystery data is still
unfathomable in a practical sense. You have to really dedicate
yourself if you want to over-comment a data structure, and you'll
probably fail anyway. Functions, on the other hand, can be
over-commented almost instantly. When it comes to commenting, make
sure your data structures get *lots* of love, but don't sweat your
functions so much.
In those rare circumstances where an incredible subtlety is at play,
or an imperfection which cannot be solved at the moment needs a note
to remind you to fix it, beefy function comments may be merited (but
exercise prodigious discretion). On the whole, however, everything
you learned in Comp Sci, if anything at all, is totally wrong and
should be ignored/forgotten ASAP.
But I Want To Do It My Way
==========================
Fine, be a bitch. Just run the following indent command when you're
done, and you'll probably get acceptable results.
indent -kr -bad -bl -bls -bli0 -bs -nce
Misc
====
Use spacing to your advantage. The human mind works really well with
a table based layout. The following:
int function_way_too_freakin_long(); /* blistered earth rules */
int function_one(int foo); /* metallica sucks */
int function_twenty(int bar); /* was anyone honestly surprised about halford? */
Is much more readable when laid out thusly:
int function_way_too_freakin_long (); /* blistered earth rules */
int function_one (int foo); /* metallica sucks */
int function_twenty (int bar); /* was anyone honestly surprised about halford? */
This kind of thing is typically seen in header files, but don't be
afraid to use the same technique to clean up intricate code that tends
to induce migraines in whomsoever attempts to read it.
At the time of this writing [2004-06-06], lots of Specimen blatantly
disregards the above rules. So sue me, I was (am) just starting out.
I'm working on fixing that. Hopefully, by the time anybody reads this
doc, this clause will no longer be relevant.
|