-
Notifications
You must be signed in to change notification settings - Fork 0
Coding standard
(wip)
This guide aims to explain the coding standards that I as the lead developer expect. Consistent coding style is important to ensure that your code is readable by anyone in the project, and makes maintenance of the code far easier, as well as making errors easier to track down.
...use clang-format with its default settings. It typically does a great job at formatting your code to comply with almost all that this document presents.
You may download clang-format and other LLVM clang tools here
clang-format -i filename.cIndent your code with two spaces ( ). Do not use the tab character (\t).
Good
int main() {
if (something()) {
do_something_useful();
}
return 0;
}Bad
int main() {
if (something()) {
do_something_useful();
}
return 0;
}Use C-style comments (/* comment */), do not use C++ comments (// comment)
Good
/* Some comment */
...Bad
// Some comment
...Comment must be on its own line. Do not put the comment on a line with code.
Good
/* Comment */
some_code();Bad
some_code(); /* Comment */We use doxygen for docs. Put the documentation in the header files, not the source files. The precise style of documentation is as follows:
/**
* @brief A short sentence describing what the function does, ending with a full-stop (dot).
*
* A more detailed description. May span multiple
* lines or sentences. This is optional but highly
* recommended.
*
* ```
* example of usage here
* ```
*
* @param p Description of the parameter
* @return Description of the return value
*/
int func(int p);Example
/**
* @brief Checks whether or not the game should exit.
*
* ```
* int main() {
* GameState *state = (Gamestate *)malloc(sizeof(GameState));
*
* while (!game_should_exit(state)) {
* game_logic(state);
* }
*
* free(state);
*
* return 0;
* }
* ```
*
* @param state Current game state
* @return uint8_t Whether or not the game should exit.
*/
uint8_t game_should_exit(GameState *state);Always name variables something useful. Ideally the variable should be a brief description of what it's supposed to do.
Good
float velocity = 1.0f;
float mass = 10.0f;
float momentum = velocity * mass;Bad
float a = 1.0f;
float b = 10.0f;
float c = a * b;The goal of a consistent variable name style is to always be able to tell what kind of a thing each variable or identifier (name) is simply by looking at its name. This significantly speeds up the development process as you no longer need to rely on your IDE to tell you what you're looking at. The style we'll be using is inspired by the style of the Ruby programming language.
Please always use snake_case for local (scoped) variable names and function argument names. Use SCREAMING_SNAKE_CASE for globals and #define'd constants.
Good
#define PLAYER_FRICTION 0.99f;
...
float calculate_momentum(float player_velocity, float player_mass) {
float momentum = player_velocity * player_mass;
return momentum * PLAYER_FRICTION;
}Bad
#define PlayerFriction = 0.99f;
float calculateMomentum(float PlayerVelocity, float playerMass) {
float MOMENTUM = PlayerVelocity * playerMass;
return MOMENTUM * PlayerFriction;
}Function names should always use snake_case.
Good
int function_name() { }
int do_something_useful() { }
int player_kill(Player *player) { }Bad
int functionName() { }
int DoSomethingUseful() { }
int PLAYERKILL(Player *player) { }Structs and classes should always use CamelCase.
Good
typedef struct Player {
...
} Player;class PlayerData {
...
};Bad
typedef struct player {
...
} player;class playerData {
...
};Everything should be private by default. Only use public if you really need to have a method/variable externally-available.
Good
class Foo {
public:
Vector3 velocity;
void do_thing();
private:
int buffer_position;
float internal_float;
void determine_how_to_do_thing();
};Bad
class Foo {
public:
Vector3 velocity;
int buffer_position;
float internal_float;
void do_thing();
void determine_how_to_do_thing();
};Try to separate the "logical" blocks of your program by using newlines. They make it much easier to read your code. The logical blocks are variables or function calls that vaguely share the same overall "theme" or goal.
Here's when to put a newline:
- After a block of variable declarations
- After closing bracket (
})- UNLESS the next line only contains a closing bracket
- After a block of function calls
- Before
if,for,whileand other logical blocks - Before
caselabel - Before
returnstatement - Before and after
#ifdef / #ifndef - Before and after
#endif - After a block of
#definestatements - After a block of
#includestatements - At the very end of the file. Your files should end with a single empty line.
Here's when NOT to put a newline
- At the start of the file
- After two consequent newlines (avoid having 2 empty lines next to each other)
- Directly after block opening (after
{)
Good
#include <iostream>
#ifdef _WIN32
typedef WideChar char16_t
#endif
int main() {
const int a = 123;
const float b = 1.0f;
const GameState *state = game_new_state();
if (game_is_paused(state)) {
switch (state->status) {
case Status::WIN:
game_win(state);
break;
case Status::LOSS:
game_loss(state);
break;
default:
game_loss(state);
}
return 0;
} else {
if (state->tick > a)
return 1;
game_tick(state);
}
return 0;
}Bad
#include <iostream>
#ifdef _WIN32
typedef WideChar char16_t
#endif
int main() {
const int a = 123;
const float b = 1.0f;
const GameState *state = game_new_state();
if (game_is_paused(state)) {
switch (state->status) {
case Status::WIN:
game_win(state);
break;
case Status::LOSS:
game_loss(state);
break;
default:
game_loss(state);
}
return 0;
} else {
if (state->tick > a)
return 1;
game_tick(state);
}
return 0;
}In general, no spaces after opening brackets, and before closing brackets. The only exception are curly brackets ({ }). You should put spaces before opening round brackets (() and after closing round brackets ()). You should put a space after closing square bracket ([).
You should also surround basic binary operators (+ - / * == || && and others) by spaces on both sides.
When defining a pointer, put a space before *, but not after.
Unary operators should not have any spacing
Good
int a[8] = { ... };
int *ptr;
if (a[0] == 10 && !a[1]) {
...
}Bad
int a[ 8 ] = {...};
int* ptr;
if( a[ 0 ]==10&& ! a [ 1 ]){
...
}Try to use const by default. Only use non-const if you absolutely cannot think of a way to use it.
Good
/* Game state is only read, so it can be const */
const GameState *game_state = ...;
...
if (game_is_paused(game_state)) {
...
}Bad
/* Game state is only read, but is mutable here. This could have consequences if you're not careful! */
GameState *game_state = ...;
...
if (game_is_paused(game_state)) {
...
}Standard libraries typically provide many useful functions. Avoid reinventing the wheel and try to find out if C11 / C++11 already have something that does what you want to do.