<< Computer Networks
Practicum: Coding Advice
// Globals that come in handy.
$DateFormat = "l \\t\h\e jS \o\f F Y";
$myname=ereg_replace('^.*/export','',$_SERVER['PATH_TRANSLATED']);
echo "Last-Modified: ".date($DateFormat, filemtime($myname)).".";
?>
- Think before you code
- Never use complex syntax
- Do not make compounds
- Do not optimize
- Use a standard debugging thing.
- Don't be afraid to use status variables
- Use proper indentation
- Read the man pages
- Use assert().
- Do not put "C-code" in header files
- Do not use funny pre-processor stuff
- Do not define true as 1
- Use { and }
- Use a C-beautifier
- Don't use global variables
- Be careful with malloc()
- Check return values
- Use names that have a large psychological distance
- Do not be afraid to use long names and standard prefixes
- Use names constants
- Do not make scores of boolean functions
- Check your programs with lint
- Think before you code. What does this code have
to do? Then code it to do that and nothing
more!
- Never use complex syntax like:
for(;P("\n"),R--;P("|"))for(e=C;e--;P("_"+(*u++/8)%2))P("| "+(*u/4)%2);
- Do not make compounds (in fact anything between
{ and }) bigger than say 20 lines.
- Do not optimize until it is really
needed. Concentrate on clean code, readable code. Do not save
on functions calls do not do loop enrolling, etc.
- Use a standard debugging thing. Like:
#ifdef DEBUG
#define dprint printf
#else
#define dprint (void)
#endif
Then only use dprint() for debug output:
dprint("Function foo has parameters %s and %d\n",foos,fooi);
- Don't be afraid to use status variables. Like:
int found;
int i;
/* Look for arg that is ok.
*/
found = 0;
i = 0;
while (!found && i < N) {
found = myok(arg[i]);
i++;
}
/* If proper arg is found, do stuff to it.
*/
if (found) {
dostuff(arg[i]);
}
So do not do:
int i;
for (i = 0; i < MAX; i++)
if (myok(arg[i])) {
dostuff(arg[i]);
break;
}
And even worse:
argp *p = arg - 1;
while (++p < arg + MAX) if (myok(*p)) {dostuff(*p); break;}
[Note added later: this point shows nicely how personal preference can creep into supposedly general advice. The second piece of code uses a very standard for-loop construction that will be recognized and understood immediately by any trained C programmer. It is short and to the point, and would be my preferred way of doing this. Ironically, the first piece of code shows how not to do it: how quickly can you spot the major bug in there? /David, Apr'10]
- Use proper indentation. Like 2 or 4 spaces, do not use
tabs in your code.
[Note added later: more importantly, use whatever indentation style is used in the code you're editing, if applicable. Otherwise, pick a style and stick to it. Tabs are not frowned upon. /David, Apr'10]
- Read the man pages of assert, alarm,
make, malloc and memcpy.
- Use assert(). See man page.
- Do not put "C-code" in header files.
- Do not use funny pre-processor stuff like:
#define cat(a,b) a##b
- Do not define true as 1. Code like this
will print nothing (with most compilers)!
#define true 1
#define false 0
x = (4 == 4);
if (x == true) {
dprint ("4 == 4\n");
}
[Note added later: whoever wrote this did not read the C standard, but the advice itself isn't bad. /David, Apr'10]
Or even worse:
typedef enum {false, true} boolean;
boolean b;
b = (i == i);
- Use { and } on every if,
when, do, for, etc.
[Note added later: we're not religious about this either. /David, Apr'10]
- Use a C-beautifier, like indent (see the man
page). There are many others available on the Internet.
- Don't use global variables where you could use parameters.
- Be careful with malloc(). Put a debug counter
in your malloc()/free() code like:
int _malloc_counter = 0;
void *my_malloc(size_t siz)
{
_malloc_counter++;
return malloc(siz);
}
void my_free(void *mem)
{
_malloc_counter--;
free(mem);
}
Then use:
dprint("Malloc counter is %d\n",_malloc_counter);
in your code where you know the values it should have. Or later
on, use:
assert(_malloc_counter == 0);
or:
assert(_malloc_counter == n_blocks + n_fragments);
or whatever.
- Check return values from all
library and system calls. Do not do:
curr_date = strstr(buf, "Date");
if(sscanf(curr_date, "%*[^:]:%[^\n]", current_date)!=1)
{
printf("Current date not set in header. [%s]\n", current_date);
return -1;
}
In fact, do not use
sscanf(), gets(), etc.
- Use names that have a large psychological distance like:
int my_first_index;
int my_last_index;
Do not use:
int indexf, indexl;
- Do not be afraid to use long names and standard prefixes
like: i_block, n_blocks, max_block_size,
t_block_fragment a_fragment[MAX_FRAGMENTS] etc. Use
i_ for index, a_ for array, t_ for
type, n_ for number, max_ for maximum,
p_ for pointer, my_ for rewrites of "known"
functions etc. Or make up your own. But stick to
them.
- Use names constants. Do not put any number but 0 and 1
in your code. Like:
#define MSG_MAX_SIZE 1024
#define MSG_ID_OFFSET 0
#define MSG_SIZE_OFFSET 6
#define MSG_COUNT_OFFSET 8
#define MSG_FLAGS_OFFSET 14
#define MSG_OK_FLAG 0x01
#define MSG_FRAGMENT_FLAG 0x02
#define MSG_LAST_FLAG 0x04
#define MSG_RESEND_FLAG 0x08
byte message[MSG_MAX_SIZE];
msg_get (message, MSG_MAX_SIZE);
if (message[MSG_FLAGS_OFFSET] & MSG_RESEND_FLAG) {
msg_retry_fit(message);
}
- Do not make scores of boolean functions. Like:
bool msg_resend_flag_set(byte flag)
{
return (flag & MSG_RESEND_FLAG) == MSG_RESEND_FLAG);
}
In fact, don't make any of this type.
- Check your programs with
lint(see man page). It will of course not
find all your bugs, but at least a few very common ones.
|