Log in | Back to darenet.org

Development Team/Coding Standards/new

m (Structure fields: correct typo)
Line 1: Line 1:
-
== Comments ==
+
This document gives coding conventions for the C code comprising many of DareNET's development projects.
-
Comments can add immensely to the readability of a program, but used heavily or poorly placed they can render good code completely incomprehensible. It is far better to err on the side of too few comments rather than too many - at least then people can find the code. Also, if your code needs a comment to be understood, then you should look for ways to rewrite the code to be clearer. And comments that aren't there won't get out of date. An inaccurate or misleading comment hurts more than a good comment helps, so be sure to update or remove your comments as needed.
+
Note, rules are there to be broken. Two good reasons to break a particular rule:
-
That being said, good places to put comments are:
+
# When applying the rule would make the code less readable, even for someone who is used to reading the code that follows the rules.
 +
# To be consistent with surrounding code that also breaks it (maybe for historic reasons) -- although this is also an opportunity to clean up someone else's mess.
-
* a broad overview at the beginning of a module
+
== C dialect ==
-
* data structure definitions
+
-
* global variable definition
+
-
* at the beginning of a function
+
-
* tricky steps within a function
+
-
If you do something weird, a comment to explain why can save future generations from wondering what drug you were on and where to get it. If you do something clever, brag about it. Not only will this inflate your ego, but it will also subtly tip off others as to where to look first for bugs. Finally, avoid fancy layout or decoration.
+
* While you may use C99, keep in mind that variable length arrays and macros with variable number of parameters are not well supported amongst most compilers. If you use these features, ensure you account for this (see services-darenet's HelpServ module for an example).
-
NOTE: DO NOT use C++ style single-line comments. It's consider bad practice to use them in a C program, and is not ANSI compliant.
+
* GCC is the compiler we use for almost all our testing. We recommend you use it as well. However, while use of GCC extensions are not prohibited, we don't necessarily encourage their use either.
-
You should also strive to doxify your comments, where suitable. Rambles, rants, and personal complaints do not provide any benefit to understanding code, please do not add them.
+
* Never use C++ style // single line comments.
-
'''Examples:'''
+
== Code lay-out ==
-
<c>/* single line comments look like this */
+
* Tabs, tabs, ONLY tabs. Use a single tab for each level of indentation.
-
/*
+
* No line should be longer than 80 characters. If this and the previous rule together don't give you enough room to code (e.g., most of us have our editors configured to render one tab as four spaces), your code is too complicated -- consider using subroutines.
-
* Important single line comments look like multi-line comments.
+
-
*/
+
-
/*
+
* No line should end in whitespace. If you think you need significant trailing whitespace, thing again -- somebody's editor might delete it as a matter of routine.
-
* Multiline comments look like this. Put the opening and closing
+
-
* comment sequences on lines by themselves. Use complete sentences
+
-
* with proper English grammar, capitalization, and punctuation.
+
-
*/
+
-
/* but you don't need to punctuate or capitalize one-liners */
+
* Function definition style: function name in column 1, outermost curly braces in column 1, blank line after local variable declerations. For example:
-
/**
+
<c>
-
* This is a doxified comment.
+
static void
-
*/
+
engine_set_events(struct Socket *sock, unsigned new_events)
-
</c>
+
{
 +
    struct epoll_event evt;
-
The opening / of all comments should be indented to the same level as the code to which it applies, for example:
+
    assert(0 != sock);
-
 
+
    set_events(sock, s_state(sock), new_events, &evt);
-
<c>if (fubar()) {
+
    ...
-
/*
+
-
* Fouled up beyond all recognition.  Print a nastygram
+
-
* and attempt to clean up.  If that doesn't work,
+
-
* die horribly, and try to crash the system while
+
-
* we're at it.
+
-
*/
+
-
...
+
}</c>
}</c>
-
If you put a comment on the same line as code, set it off from the code with a few tabs. Don't continue such a comment across multiple lines. For example:
+
* Code structure: one space between keywords like 'if', 'for' and the following left paren; no spaces inside the paren; braces as shown:
-
<c>printf("hi\n"); /* hello revisited */</c>
+
<c>if (mro != NULL) {
-
 
+
    ...
-
In fact, try to avoid such comments altogether - if it`s not important enough to warrant a complete sentence, does it really need to be said?
+
}
-
 
+
else {
-
== Declarations and Types ==
+
     ...
-
 
+
}</c>
-
Provide typedefs for all struct and union types, and put them before the type declarations. Creating the typedef eliminates clutter of extra <code>struct</code> and <code>union</code> keywords (we can see that it's a type from it's position in the declaration), and makes your structures look like first-class types in the language. Putting the typedefs before the type declarations allows them to be used when declaring circular types. It is also nice to have a list of all new reserved words up front.
+
-
 
+
-
'''Examples:'''
+
-
 
+
-
<c>typedef struct Foo Foo;
+
-
typedef struct Bar Bar;
+
-
 
+
-
struct Foo {
+
-
    Bar *bar;
+
-
};
+
-
 
+
-
struct Bar {
+
-
     Foo *foo;
+
-
};</c>
+
-
 
+
-
This gives a particularly nice scheme of exporting opaque objects in header files.
+
-
 
+
-
In <code>header.h</code>:
+
-
 
+
-
<c>typedef struct Foo Foo;</c>
+
-
 
+
-
In <code>source.c</code>:
+
-
 
+
-
<c>#include "header.h"
+
-
 
+
-
struct Foo { .. };</c>
+
-
 
+
-
Then a user of <code>header.h</code> can declare:
+
-
 
+
-
<c>Foo *foo;</c>
+
-
 
+
-
but cannot access the contents of Foo. In addition, the user cannot declare a plain (non pointer) Foo, and so is forced to go through whatever allocation routines you provide. We encourage this modularity technique.
+
-
 
+
-
Don't mix declarations with type definitions; i.e., don't do:
+
-
 
+
-
<c>struct Foo {
+
-
    int x;
+
-
} object;
+
-
 
+
-
or
+
-
typedef struct {
+
* The return statement should ''not'' get redundant parentheses:
-
    int x;
+
-
} type;</c>
+
-
All typedefs should stand out by themselves.
+
<c>return result;    /* correct */
 +
return (result);  /* incorrect */</c>
-
=== Structure fields ===
+
* Function and macro call style: foo(a, b, c) -- no space before the open paren, no spaces inside the parens, no spaces before commas, one space after each comma.
-
Declare each field of a structure on a line by itself. Take time to think about the order of the fields. Try to keep related fields grouped. Within groups of related fields, try and pick some uniform scheme for organizing them (e.g., alphabetically or by frequency of use). When all other considerations are equal, place larger fields first, as C's alignment rules may then permit the compiler to save space by not introducing "holes" in the structure layout.
+
* Always put spaces around assignment, Boolean and comparison operators. In expressions using a lot of operators, add spaces around the outermost (lowest-priority) operators.

Revision as of 11:48, 10 June 2010

This document gives coding conventions for the C code comprising many of DareNET's development projects.

Note, rules are there to be broken. Two good reasons to break a particular rule:

  1. When applying the rule would make the code less readable, even for someone who is used to reading the code that follows the rules.
  2. To be consistent with surrounding code that also breaks it (maybe for historic reasons) -- although this is also an opportunity to clean up someone else's mess.

C dialect

  • While you may use C99, keep in mind that variable length arrays and macros with variable number of parameters are not well supported amongst most compilers. If you use these features, ensure you account for this (see services-darenet's HelpServ module for an example).
  • GCC is the compiler we use for almost all our testing. We recommend you use it as well. However, while use of GCC extensions are not prohibited, we don't necessarily encourage their use either.
  • Never use C++ style // single line comments.

Code lay-out

  • Tabs, tabs, ONLY tabs. Use a single tab for each level of indentation.
  • No line should be longer than 80 characters. If this and the previous rule together don't give you enough room to code (e.g., most of us have our editors configured to render one tab as four spaces), your code is too complicated -- consider using subroutines.
  • No line should end in whitespace. If you think you need significant trailing whitespace, thing again -- somebody's editor might delete it as a matter of routine.
  • Function definition style: function name in column 1, outermost curly braces in column 1, blank line after local variable declerations. For example:
static void
engine_set_events(struct Socket *sock, unsigned new_events)
{
    struct epoll_event evt;
 
    assert(0 != sock);
    set_events(sock, s_state(sock), new_events, &evt);
    ...
}
  • Code structure: one space between keywords like 'if', 'for' and the following left paren; no spaces inside the paren; braces as shown:
if (mro != NULL) {
    ...
}
else {
    ...
}
  • The return statement should not get redundant parentheses:
return result;    /* correct */
return (result);  /* incorrect */
  • Function and macro call style: foo(a, b, c) -- no space before the open paren, no spaces inside the parens, no spaces before commas, one space after each comma.
  • Always put spaces around assignment, Boolean and comparison operators. In expressions using a lot of operators, add spaces around the outermost (lowest-priority) operators.