User:Panic2k4/Sandbox/TiC
Appearance
< User:Panic2k4 | Sandbox
Favorite Coding standard and Guidelines
[edit | edit source]Please when making changes try to apply the standards to any surrounding code. This is especially true of comments and variable naming.
Indentation and Spacing
[edit | edit source]Braces
- Braces shall follow "Extended Style".
- The Extended Bracing Style means that the curly brace pair are lined up with the surrounding statement. Statements and declarations between the braces are indented relative to the braces.
- Braces shall be indented 2 columns to the right of the starting position of the enclosing statement or declaration.
- Loop and conditional statements shall always have brace enclosed sub-statements.
- The code looks more consistent if all conditional and loop statements have braces.
Even if there is only a single statement after the condition or loop statement today, there might be a need for more code in the future.
- The code looks more consistent if all conditional and loop statements have braces.
- Braces without any contents or a single statement may be placed on the same line.
Lines
- Use blank lines to improve readability.
- They separate blocks of code which are in themselves logically related.
- Lines shall not exceed 79 characters.
- Even if your editor handles long lines, other people may have set up their editors differently. Long lines in the code may also cause problems for other programs and printers.
- Each statement shall be placed on a line on its own.
- There is no need to make code compact. Putting several statements on the same line only makes the code cryptic to read.
Spaces
- No space between a function name and the parenthesis " (" starting its parameter list.
- All binary arithmetic, bitwise and assignment operators and the ternary conditional operator (?:) shall be surrounded by spaces; the comma operator shall be followed by a space but not preceded; all other operators shall not be used with spaces.
- Do not use tabs.
- Tabs make the source code difficult to read where different programs treat the tabs differently. The same code can look very differently in different views.
Avoid using tabs in your source code to avoid this problem. Use spaces instead.
- Tabs make the source code difficult to read where different programs treat the tabs differently. The same code can look very differently in different views.
Entity Naming
[edit | edit source]- Entity naming shall be done in English.
- Enables internationalization of the code.
- Use sensible, descriptive names.
- Do not use short cryptic names or names based on internal jokes. It shall be easy to type a name without looking up how it is spelt.
Exception: Loop variables and variables with a small scope (less than 20 lines) may have short names to save space if the purpose of that variable is obvious.
- Do not use short cryptic names or names based on internal jokes. It shall be easy to type a name without looking up how it is spelt.
- Only use English names.
- It is confusing when mixing languages for names. English is the preferred language because of its spread in the software market and because most libraries used already use English.
- Variables with a large scope shall have long names, variables with a small scope can have short names.
- Scratch variables used for temporary storage or indices are best kept short. A programmer reading such variables shall be able to assume that its value is not used outside a few lines of code. Common scratch variables for integers are i, j, k, m, n and for characters c and d.
- Use namespaces for identifiers declared in different modules
- This avoids name clashes.
- Use name prefixes for identifiers declared in different modules
- This avoids name clashes.
- Function names must have first letter of every word in caps.
- Member functions should be named after actions
- Examine the contract between the member function and its client
- Name things after what they represent.
- If you can't think of what it is that is a clue you have not thought through the design well enough.
- Include Units in Names
- If it is a representation of time, weight, or some other unit then include the unit in the name so developers can more easily spot problems.
Comments
[edit | edit source]- Comments shall be written in English.
- Comments shall use the C++-style whenever possible but C style is possible for in a line mid code commenting and multi-line function introductory comment. (except contructors/destructors)
- All comments shall be placed above the line the comment describes, indented identically or after the code in the same line.
- Being consistent on placement of comments removes any question on what the comment refers to.
- Every class shall have a comment that describes its purpose.
- Every function should have a comment that describes its purpose.
- Constant names must always be all caps.
- Function comments should include any precondition and postcondition and side effects.
- Parameter comments must indicate change of ownership.
Files
[edit | edit source]- C++ source files shall have extension ".c".
- C++ header files shall have extension ".h".
- There should only be one externally visible class defined in each header file.
- Having as few declarations as possible in a header file reduces header dependencies.
- The header file shall have the same name as the class plus extension ".h".
- External non-member functions that belong to the class interface may also be declared in the same header file.
- File names shall be treated as case sensitive.
- Files must have the "#pragma once" include guards.
- System header files shall be included with <> and project headers with "".
- Put #include directives at the top of files.
- Having all #include directives in one place makes it easy to find them.
- Do not use absolute directory names in #include directives.
- The directory structure may be different on other systems.
Declarations
[edit | edit source]- Provide names of parameters in function declarations.
- Parameter names are useful to document what the parameter is used for.
The parameter names shall be the same in all declarations and definitions of the function.
- Parameter names are useful to document what the parameter is used for.
- Use a typedef to define a pointer to a function.
- Pointers to functions have a strange syntax. The code becomes much clearer if you use a typedef for the pointer to function type. This typedef name can then be used to declare variables etc.
- Declare each item in a separate declaration.
- One declaration per line. It avoids the problem of knowing which variables are pointers.
int* p, i;
It is easy to forget that the star belongs to the declared name, not the type, and look at this and say that the type is "pointer to int" and both p and i are declared to this type. It also encourages commenting and it is easier to read.
- One declaration per line. It avoids the problem of knowing which variables are pointers.
- Avoid use of exception specifications.
- Exception specifications in C++ are not as useful as they look. The compiler does not make the code more efficient. On the contrary, the compiler has to insert code to check that called functions do not violate the specified exception specification at runtime.
- Declare inherited functions virtual.
- An inherited function is implicitly virtual if it is declared virtual in the base class. Repeat the virtual keyword when declaring an inherited function in a derived class to make it clear that this function is virtual.
- Do not use global using declarations and using directives in headers.
- Bringing in names from a namespace to the global namespace may cause conflicts with other headers. The author of a header does not know in which context the header is used and should avoid polluting the global namespace. Instead, only use using declarations in the source files.
- Do not use using directives.
- Bringing in names from a namespace can cause all sorts of problems as the namespace might contain more names than you would expect.
- Declare class data private.
- Classes shall encapsulate their data and only provide access to this data by member functions to ensure that data in class objects are consistent.
The exception to the rule is C type struct that only contains data members.
- Classes shall encapsulate their data and only provide access to this data by member functions to ensure that data in class objects are consistent.
- Only use the keyword struct for C-style structs.
- Functions that can be implemented using public interface of a class shall not be members.
- A class definition can be kept small and less prone to change if it only defines the core functionality. Any other functions that can be implemented with this minimal class definition shall be implemented as non-member functions. They are still seen as part of the interface of the class.
Statements
[edit | edit source]- Never use gotos.
- Gotos break structured coding.
- All switch statements shall have a default label.
- Even if there is no action for the default label, it shall be included to show that the programmer has considered values not covered by case labels. If the case labels cover all possibilities, it is useful to put an assertion there to document the fact that it is impossible to get here. An assertion also protects from a future situation where a new possibility is introduced by mistake.
Other
[edit | edit source]- Avoid macros.
- Most macros can be replaced by constants, enumerations or inline functions.
As macros are not part of the C++ language, they do not provide type safety and debugger support.
- Most macros can be replaced by constants, enumerations or inline functions.
- Use parentheses within macros around parameter names.
- It's generally a good idea to use extra parentheses for macro parameters, it avoids the parameters from being parsed in a unintended ways. But there are some exceptions to consider:
- Since comma operator have lower precedence than any other, this removes the possibility of problems.
- When concatenating tokens with the ## operator, converting to strings using the # operator, or concatenating adjacent string literals, parameters cannot be individually parenthesized.
- It's generally a good idea to use extra parentheses for macro parameters, it avoids the parameters from being parsed in a unintended ways. But there are some exceptions to consider:
- Macro replacement lists should be parenthesized.
- "#define CUBE(X) (X) * (X) * (X)" as "#define CUBE(X) ((X) * (X) * (X))"
- Do not use literal numbers other than 0 and 1.
- Use constants instead of literal numbers to make the code consistent and easy to maintain. The name of the constant is also used to document the purpose of the number.
- Check all fail point, use plenty of assertions.
- Assertions are useful to verify pre-conditions, post-conditions and any other conditions that should never happen. Pre-conditions are useful to verify that functions are called with valid arguments. They are also useful as documentation of what argument value ranges a function is designed to work with.
Assertions are macros that print error messages when the condition is not met. The macros are disabled in release mode and do not cost anything in performance or used memory in the end product.
- Assertions are useful to verify pre-conditions, post-conditions and any other conditions that should never happen. Pre-conditions are useful to verify that functions are called with valid arguments. They are also useful as documentation of what argument value ranges a function is designed to work with.
- Use prefix increment/decrement instead of postfix increment/decrement when the value of the variable is not used.
- For class objects there may be two different member functions for the postfix and prefix operations. The postfix operation has to keep a temporary return value of the object before changing the object. For built-in objects this does not matter as the compiler will be able to optimize away the temporary value when it is not used.
Even if this only matters for class objects, it is a good habit to use prefix increment/decrement at all times.
- For class objects there may be two different member functions for the postfix and prefix operations. The postfix operation has to keep a temporary return value of the object before changing the object. For built-in objects this does not matter as the compiler will be able to optimize away the temporary value when it is not used.
- Write conditional expressions like: if ( 6 == errorNum ) ...
- This style avoids accidental assignments of the variable when the comparison operator is written with only one equal sign (=).
- Use the new cast operators.
- Use dynamic_cast, const_cast, reinterpret_cast and static_cast instead of the traditional C cast notation. These document better what is being performed.
- Avoid use of implicit conversion to bool in conditions.
- if ( ptr) is bad
if ( ptr != 0 ) is ok
- if ( ptr) is bad