Style Guidelines: Difference between revisions
(10 intermediate revisions by 2 users not shown) | |||
Line 4: | Line 4: | ||
=== All-encompassing Guidelines === | === All-encompassing Guidelines === | ||
==== Line endings ==== | |||
Use a single line feed character (ASCII 10) for line endings. | |||
==== Indentation ==== | ==== Indentation ==== | ||
Indent your code with tabs (ASCII 9). Use space (ASCII 32) for all other | Indent your code with tabs (ASCII 9). Use space (ASCII 32) for all other | ||
Line 10: | Line 13: | ||
==== Braces ==== | ==== Braces ==== | ||
Braces are on their own line, on the same level of indentation as the | Braces are on their own line, on the same level of indentation as the | ||
structure they belong to | 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. | <tt>if</tt> statements if the first block or an <tt>else</tt> block has them. | ||
Line 18: | Line 20: | ||
printf("Too few thingies!"); | printf("Too few thingies!"); | ||
AddMore(); | AddMore(); | ||
} else { | } | ||
else | |||
{ | |||
printf("We have enough"); | printf("We have enough"); | ||
} | } | ||
Line 25: | Line 29: | ||
Function names are not followed by space. Commas are. No space follows opening | Function names are not followed by space. Commas are. No space follows opening | ||
brackets ("[") or parentheses ("("). Also no space preceeds closing brackets | brackets ("[") or parentheses ("("). Also no space preceeds closing brackets | ||
("]") or parentheses (")"). | ("]") or parentheses (")"), or commas. "::", "->", "." and unary operators do not | ||
operators do. | require spaces. Other binary operators do. | ||
Keywords (<tt>while</tt>, <tt>for</tt> etc.) are followed by a space. | Keywords (<tt>while</tt>, <tt>for</tt> etc.) are followed by a space. | ||
Line 64: | Line 68: | ||
// Single-line comments look like this | // 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 ==== | ==== Type Casting ==== | ||
Line 82: | Line 83: | ||
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 | legal entities. | ||
/* | /* | ||
* OpenClonk, http://www.openclonk.org | * OpenClonk, http://www.openclonk.org | ||
* | * | ||
* Copyright (c) | * Copyright (c) 2009-2014, The OpenClonk Team and contributors | ||
* | * | ||
* 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 136: | 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 | easier for pretty-printers and editors. Consider undefining your macro when | ||
you are done using it. | |||
it. | |||
#define FOO(a, b) do { \ | #define FOO(a, b) do { \ | ||
bar += (a); \ | |||
bar /= (b); \ | |||
} while(0) | } while(0) | ||
==== Data Types ==== | ==== 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 163: | 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 ==== |
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.