Style Guidelines: Difference between revisions

Isilkor (talk | contribs)
Draft of style guidelines
 
Marky (talk | contribs)
 
(15 intermediate revisions by 2 users not shown)
Line 3: Line 3:
inside the examples.
inside the examples.


=== All-encompassing Guidelines ===
==== Line endings ====
Use a single line feed character (ASCII 10) for line endings.
==== Indentation ====
Indent your code with tabs (ASCII 9). Use space (ASCII 32) for all other
formatting.
==== Braces ====
Braces are on their own line, on the same level of indentation as the
structure they belong to. You may add braces around single statements in
<tt>if</tt> statements if the first block or an <tt>else</tt> block has them.
if (count < 10)
{
printf("Too few thingies!");
AddMore();
}
else
{
printf("We have enough");
}
==== Spaces ====
Function names are not followed by space. Commas are. No space follows opening
brackets ("[") or parentheses ("("). Also no space preceeds closing brackets
("]") or parentheses (")"), or commas. "::", "->", "." and unary operators do not
require spaces. Other binary operators do.
Keywords (<tt>while</tt>, <tt>for</tt> etc.) are followed by a space.
==== Parentheses ====
Do not use parentheses unless they are required for precedence or the code
gets confusing without them. Remember other people may have confusion
thresholds different from you.
==== Control Structures ====
Control structures with a single statements are written without braces. If the
statement spans multiple lines, you may add braces for readability. Structures
without a statement contain a comment denoting this.
while (*dest++ = *src++)
/* empty */;
Cascades in a <tt>switch</tt> statement are marked by a FALLTHROUGH
comment. Code that cannot be reached has an assertion. <tt>case</tt> elements
are not indented.
switch (foo)
{
case FOO_HEX:
accept_hex = true;
// FALLTHROUGH
case FOO_DEC:
accept_num = true;
break;
default:
assert(!"Invalid foo value");
// Do something meaningful here anyway, if possible;
// try to not leave the program in an ill-defined state.
}
==== Comments ====
  // Single-line comments look like this
  // Single-line comments look like this


  //
  // Multi-line comments look like this. Using C++-style comments
// Very important single-line comments look like this
// helps if you need to comment out large pieces of code later, or if the length of
  //
// the comment changes over time. Of course you could still use #if 0 ... #endif
  // to achieve that.


  /*
  /* You may also write multi-line comments like this. Make sure you write enough
  * Multi-line comments look like this. Make sure you write enough text to
    text to warrant a multi-line comment. Also be sure to write in full sentences. */
  * warrant a multi-line comment. Also be sure to write in full sentences.
 
  */
==== Type Casting ====
Do not use C-style or function style casts. Use a template cast instead.


=== Source File Layout ===
==== Copyright Header ====
Every source file begins with a copyright header. If you make significant
Every source file begins with a copyright header. If you make significant
changes to the code, you may (but are not required to) add your name to the
changes to the code, you may (but are not required to) add your name to the
list of copyright holders. If you choose to add yourself, use your real name,
list of copyright holders in <tt>COPYING</tt>. If you choose to add yourself, use your real name,
not a nickname. Legally recognized pseudonyms are accepted, as are names of
not a nickname. Legally recognized pseudonyms are accepted, as are names of
legal entities. If you don't want to add yourself, you may add the catch-all
legal entities.
copyright attribution phrase, if it does not already exist.


  /*
  /*
   * OpenClonk, http://www.openclonk.org
   * OpenClonk, http://www.openclonk.org
   *
   *
   * Copyright (c) 2000-2009  John Doe
   * Copyright (c) 2009-2014, The OpenClonk Team and contributors
  * Copyright (c) 2005  Jane Q. Public
  *
  * Portions might be copyrighted by other authors who have contributed
  * to OpenClonk.
   *
   *
   * Other legalese goes here, but has been omitted for brevity. See an
   * Other legalese goes here, but has been omitted for brevity. See an
Line 37: Line 99:
the purpose of the file next, and leave another blank line after this.
the purpose of the file next, and leave another blank line after this.


==== Inclusion Guards ====
If you are writing a header file, use #include guards. If your file is called
If you are writing a header file, use #include guards. If your file is called
''C4Foo.h'', your guard should be <tt>INC_''C4Foo''</tt>.
''C4Foo.h'', your guard should be <tt>INC_''C4Foo''</tt>.
Line 47: Line 110:
''TODO: Precompiled headers.''
''TODO: Precompiled headers.''


Include system headers first. Put the filename in angle brackets, and use
==== #include Directives ====
Include local headers first. Put the filename in double quotes, and use
forward slashes as directory separators.
forward slashes as directory separators.


  #include <vector>
  #include "Standard.h"
#include "StdBuf.h"


Leave a blank line before local headers. Use double quotes to include these,
Leave a blank line before system headers. Use angle brackets to include these,
and sort them alphabetically.
and sort them alphabetically.


  #include "Standard.h"
  #include <map>
  #include "StdBuf.h"
  #include <vector>


=== Declarations ===
==== Preprocessor Macros ====
Do not <tt>#define</tt> values in headers. Use <tt>const</tt> instead, or
Do not <tt>#define</tt> values in headers. Use <tt>const</tt> instead, or
<tt>enum</tt> if you are declaring an enumeration.
<tt>enum</tt> if you are declaring an enumeration.
Line 65: Line 132:
a <tt>template</tt>.
a <tt>template</tt>.


If, despite of the above, still need to write a macro, use an all-uppercase
If, despite of the above, you still need to write a macro, use an all-uppercase
name. If your macro contains a compound statement, enclose it in a <tt>do</tt>
name. If your macro contains a compound statement, enclose it in a <tt>do</tt>
loop to allow its use in <tt>if</tt> statements. A terminating semicolon
loop to allow its use in <tt>if</tt> statements. A terminating semicolon
should be provided at the place of invocation. This makes parsing the source
should be provided at the place of invocation. This makes parsing the source
easier for pretty-printers and editors. If your macro spans multiple lines,
easier for pretty-printers and editors. Consider undefining your macro when
align the backslashes.
you are done using it.


  #define FOO(a, b) do { \
  #define FOO(a, b) do { \
  bar += (a);         \
bar += (a); \
  bar /= (b);         \
bar /= (b); \
  } while(0)
  } while(0)


==== Data Types ====
Do not use the Win32 style integer declarations <tt>DWORD</tt> and
Do not use the Win32 style integer declarations <tt>DWORD</tt> and
<tt>BOOL</tt>. If you need a guarantee about the size of your variables, use
<tt>BOOL</tt> except when interfacing with the Windows API. If you need a guarantee about the size of your variables, use
the C99 types <tt>int''XX''_t</tt> and <tt>uint''XX''_t</tt>. If you don't
the C99 types <tt>int''XX''_t</tt> and <tt>uint''XX''_t</tt>. If you don't
need that guarantee, use <tt>int</tt>. If you need a variable that is large
need that guarantee, use <tt>int</tt>. If you need a variable that is large
Line 90: Line 158:
after. This saves some confusion when declaring multiple variables at once.
after. This saves some confusion when declaring multiple variables at once.
The same goes for references.
The same goes for references.
Assign variable values in separate lines, because this improves readability. Do not assign variable values and declare other variables of the same type in the same line, because this reduces readability.


  int *foo, *bar;
  int *foo, *bar;
  char *Qux(const char *quux);
  char *Qux(const char *quux);
int a = 1;
int b = 2;
int c, d, e;


==== Functions ====
Functions that are not used outside of the containing file are placed inside
Functions that are not used outside of the containing file are placed inside
of an anonymous namespace.
of an anonymous namespace.


  namespace {
  namespace
{
  int Frobnicate(const char *foo);
  int Frobnicate(const char *foo);
  }
  }
Line 111: Line 186:


  XmlDocument *ParseXmlFile(const char *file);
  XmlDocument *ParseXmlFile(const char *file);
No class member variable should be declared <tt>public</tt>. Use
<tt>GetFoo</tt> and <tt>SetFoo</tt> accessors. If you want to declare a
compound data type that allows direct access to its members, use
<tt>struct</tt>. Do not add more functions than constructors, destructors, and
assignment operators to <tt>struct</tt>s.


When passing arguments that may be changed by the called function, pass them
When passing arguments that may be changed by the called function, pass them
as pointers. This makes it obvious that they may be changed. Use constant
as pointers. This makes it obvious that they may be changed. Use constant
references for all other parameters, unless they are a primitive type.
references for all other parameters, unless they are a primitive type.
==== Class Members ====
No class member variable should be declared <tt>public</tt> unless necessary.
Consider using <tt>GetFoo</tt> and <tt>SetFoo</tt> accessors. If you want to
declare a compound data type that allows direct access to its members, use
<tt>struct</tt>. Do not add more functions than constructors, destructors, and
assignment operators to <tt>struct</tt>s.


Mark all class members that do not change the visible state of the object
Mark all class members that do not change the visible state of the object
<tt>const</tt>. If you need to modify internal state that is not visible from
<tt>const</tt>. If you need to modify internal state that is not visible from
outside of the class, mark the state variable <tt>mutable</tt>.
outside of the class, mark the state variable <tt>mutable</tt>.
Do not use C-style casts. Use a template cast instead.
All classes and functions should have a comment explaining their purpose. This
comment is prepended to the prototype or class definition. If the function is
a local function without a prototype, it goes directly in front of the
definition. The comment uses [http://www.doxygen.org/ Doxygen] formatting.
/**
  * Make light.
  * \param book Object to enlighten.
  */
void Frotz(Spellbook *book);
Elements in a <tt>switch</tt> statement are ordered alphabetically unless
parts of the <tt>switch</tt> cascade. Cascades are marked by a FALLTHROUGH
comment. Code that cannot be reached has an assertion. <tt>case</tt> elements
are not indented.
switch (foo)
{
case FOO_HEX:
accept_hex = true;
// FALLTHROUGH
case FOO_DEC:
accept_num = true;
break;
default:
assert(!"Invalid foo value");
}
Keywords (<tt>while</tt>, <tt>for</tt> etc.) are followed by a space. Control
structures with a single statements are written without braces. If the
statement spans multiple lines, you may add braces for readability. Structures
without a statement contain a comment denoting this.
while (*dest++ = *src++)
/* empty */;
Indent your code with tabs (ASCII 9). Use space (ASCII 32) for all other
formatting.
Braces are on their own line, on the same level of indentation as the
structure they belong to. Braces around <tt>else</tt> may stand on the same
line as the <tt>else</tt>. You may add braces around single statements in
<tt>if</tt> statements if the first block or an <tt>else</tt> block has them.
if (count < 10)
{
printf("Too few thingies!");
AddMore();
} else {
printf("We have enough");
}
Function names are not followed by space. Commas are. No space follows opening
brackets ("[") or parentheses ("("). Also no space preceeds closing brackets
("]") or parentheses (")"). Unary operators do not require spaces. Binary
operators do.
Do not use parentheses unless they are required for precedence or the code
gets confusing without them. Remember other people may have confusion
thresholds different from you.

Latest revision as of 17:03, 17 June 2019

This document specifies the preferred source code style of files inside the OpenClonk source tree. Some of the style rules are also stated implicitly inside the examples.

All-encompassing Guidelines

Line endings

Use a single line feed character (ASCII 10) for line endings.

Indentation

Indent your code with tabs (ASCII 9). Use space (ASCII 32) for all other formatting.

Braces

Braces are on their own line, on the same level of indentation as the structure they belong to. You may add braces around single statements in if statements if the first block or an else block has them.

if (count < 10)
{
	printf("Too few thingies!");
	AddMore();
}
else
{
	printf("We have enough");
}

Spaces

Function names are not followed by space. Commas are. No space follows opening brackets ("[") or parentheses ("("). Also no space preceeds closing brackets ("]") or parentheses (")"), or commas. "::", "->", "." and unary operators do not require spaces. Other binary operators do.

Keywords (while, for etc.) are followed by a space.

Parentheses

Do not use parentheses unless they are required for precedence or the code gets confusing without them. Remember other people may have confusion thresholds different from you.

Control Structures

Control structures with a single statements are written without braces. If the statement spans multiple lines, you may add braces for readability. Structures without a statement contain a comment denoting this.

while (*dest++ = *src++)
	/* empty */;

Cascades in a switch statement are marked by a FALLTHROUGH comment. Code that cannot be reached has an assertion. case elements are not indented.

switch (foo)
{
case FOO_HEX:
	accept_hex = true;
	// FALLTHROUGH
case FOO_DEC:
	accept_num = true;
	break;
default:
	assert(!"Invalid foo value");
	// Do something meaningful here anyway, if possible;
	// try to not leave the program in an ill-defined state.
}

Comments

// Single-line comments look like this
// Multi-line comments look like this. Using C++-style comments
// helps if you need to comment out large pieces of code later, or if the length of
// the comment changes over time. Of course you could still use #if 0 ... #endif
// to achieve that.
/* You may also write multi-line comments like this. Make sure you write enough
   text to warrant a multi-line comment. Also be sure to write in full sentences. */

Type Casting

Do not use C-style or function style casts. Use a template cast instead.

Source File Layout

Copyright Header

Every source file begins with a copyright header. If you make significant changes to the code, you may (but are not required to) add your name to the list of copyright holders in COPYING. If you choose to add yourself, use your real name, not a nickname. Legally recognized pseudonyms are accepted, as are names of legal entities.

/*
 * OpenClonk, http://www.openclonk.org
 *
 * Copyright (c) 2009-2014, The OpenClonk Team and contributors
 *
 * Other legalese goes here, but has been omitted for brevity. See an
 * existing file for a template.
 */

The copyright header is followed by an empty line. Put a comment explaining the purpose of the file next, and leave another blank line after this.

Inclusion Guards

If you are writing a header file, use #include guards. If your file is called C4Foo.h, your guard should be INC_C4Foo.

#ifndef INC_C4Foo
#define INC_C4Foo
class C4Foo;
#endif

TODO: Precompiled headers.

#include Directives

Include local headers first. Put the filename in double quotes, and use forward slashes as directory separators.

#include "Standard.h"
#include "StdBuf.h"

Leave a blank line before system headers. Use angle brackets to include these, and sort them alphabetically.

#include <map>
#include <vector>

Declarations

Preprocessor Macros

Do not #define values in headers. Use const instead, or enum if you are declaring an enumeration.

Do not #define inline functions either, use inline. If your functions need to work on multiple data types, overload the function or write a template.

If, despite of the above, you still need to write a macro, use an all-uppercase name. If your macro contains a compound statement, enclose it in a do loop to allow its use in if statements. A terminating semicolon should be provided at the place of invocation. This makes parsing the source easier for pretty-printers and editors. Consider undefining your macro when you are done using it.

#define FOO(a, b) do { \
	bar += (a); \
	bar /= (b); \
} while(0)

Data Types

Do not use the Win32 style integer declarations DWORD and BOOL except when interfacing with the Windows API. If you need a guarantee about the size of your variables, use the C99 types intXX_t and uintXX_t. If you don't need that guarantee, use int. If you need a variable that is large enough to store a pointer on your current platform, use intptr_t.

If you come across code that still uses Win32 types, consider changing it if you are working on code in the vicinity. Don't commit changes that only consist of replacing DWORD by uint32_t.

When declaring a pointer, put a space in front of the asterisk, and none after. This saves some confusion when declaring multiple variables at once. The same goes for references.

Assign variable values in separate lines, because this improves readability. Do not assign variable values and declare other variables of the same type in the same line, because this reduces readability.

int *foo, *bar;
char *Qux(const char *quux);
int a = 1;
int b = 2;
int c, d, e;

Functions

Functions that are not used outside of the containing file are placed inside of an anonymous namespace.

namespace
{
	int Frobnicate(const char *foo);
}

Functions that are used across multiple files are prototyped inside a common header. The prototypes should be grouped where appropriate, and ordered logically or, failing that, alphabetically.

Function and class names begin with a capital letter, and use camel casing. If you need to embed acronyms inside the name, pretend the acronym was all lower case. Member variables use the same convention, but begin with a lower case letter. Do not use hungarian prefixes.

XmlDocument *ParseXmlFile(const char *file);

When passing arguments that may be changed by the called function, pass them as pointers. This makes it obvious that they may be changed. Use constant references for all other parameters, unless they are a primitive type.

Class Members

No class member variable should be declared public unless necessary. Consider using GetFoo and SetFoo accessors. If you want to declare a compound data type that allows direct access to its members, use struct. Do not add more functions than constructors, destructors, and assignment operators to structs.

Mark all class members that do not change the visible state of the object const. If you need to modify internal state that is not visible from outside of the class, mark the state variable mutable.