Confidential. © 2009-2015 Crytek Gmbh. All Rights Reserved. Page
Total Page:16
File Type:pdf, Size:1020Kb
With CRYENGINE 5.1.0, we have deprecated the support for Visual Studio 2012 and 2013. For more information, please check Visual Studio Supported Versions. This has implications on the language features that can be used in the code-base. This document outlines the most important coding standards that are applicable to CRYENGINE. Its main purpose is to achieve overall code consistency and software structural quality. It is a helper for improving code readability and easing maintenance. Programmers are expected to follow this standard while writing code for CRYENGINE. There may be few exceptions to deviate from the coding standard, since we cannot predict every scenario or situation that may occur in the future. The majority of code should follow these rules, so that we can have a clearer and maintainable code base. These rules apply to CRYENGINE, Sandbox and plug-in/extensions thereof. (All the code can be found under Code/CryEngine, Code/Sandbox and Code/CryExtensions) When you intend to deviate from the guidelines, you should mention this in the code review so that: Reviewer spends less time marking them. You can immediately state the reason for the deviation to avoid any confusion. Coding standard Disabled C++ features Uncrustify code formatting tool Common rules: Tabs and spaces Spaces in expressions Long and complex expressions Wrapping Long function parameter lists if statement for statement Infinite loops switch statement Conditional operator (ternary) Constructor initialization lists Formatting rules for composite types Naming conventions General naming rules Namespaces, using directives Class name Struct name Interface name Custom type name (typedef, using) Primitive types Enum names Template name Function name Complement names Non-member variable name Member variable name Global variable name Static variable name Thread-local storage variable name Macro name Variable naming prefixes File naming Copyright notice Implementation details in common interfaces Layout of C++ classes header files source files C++11 and newer, on the use of Modern C++ Using std::enable_if Using smart pointers Code quality Globals Macros Pointers and memory Const correctness Numeric compile-time constants Best practices Commenting Preprocessor CRT Memory allocation Standard Template Library (STL) Strings Compiler-specific features Confidential. © 2009-2015 Crytek GmbH. All Rights Reserved. Page 1 of 23 Undefined behavior Miscellaneous Express your intentions clearly Reduce code complexity Get rid of shared mutable state Disabled C++ features The CRYENGINE codebase is written in C++. The use of C language is discouraged, but may be appropriate for interactions with 3rd party C libraries, at your discretion. These features are disabled at the compiler level for all CRYENGINE modules, and cannot be used: Exceptions Run-time type information (RTTI) dynamic_cast operator Some plugins or extensions may (at their discretion) enable one or more of these features. However, it is then the responsibility of those plug-in or extension to ensure that no exceptions can propagate into the CRYENGINE modules, as this may cause undefined behavior. RTTI must be assumed to be incompatible across modules (use it only with types from the containing module). Uncrustify code formatting tool We recommend using our customized Uncrustify code formatting tool to format the code according to the rules described in this document. It can be found in <root>/Code/Tools/uncrustify, along with a config file (CryEngine_uncrustify.cfg). Note that any deviation from the guidelines introduced by the tool that cannot be formatted is acceptable. Unfortunately, no tool is 100% accurate, however if there is a systematic issue please inform the tool maintainer so that they can try to fix it. Common rules: Curly brackets should not be in the same line with other text (allowed exclusions are short single-liners in header files: constructors/destructors and get/set-like functions) Opening and closing curly brackets should be on the same column (allowed exclusions are '{}' in header files and single-liners mentioned above) When changing code in another module, mimic the style which is already present in the module Use one statement on each code line which: helps setting debugger breakpoints simplifies reading simplifies code merging allows to add an end-of-line comment easily when required A sample code block is outlined below: Confidential. © 2009-2015 Crytek GmbH. All Rights Reserved. Page 2 of 23 Example // good CMyGoodBar() : m_memberA(0) , m_memberB(0) { } // acceptable (exclusion) CMyGoodBar() : m_memberA(0) , m_memberB(0) {} // acceptable (exclusion) CMyGoodBar() : m_memberA(0), m_memberB(0) {} // bad CMyGoodBar() : m_memberA(0) , m_memberB(0) { } // bad CMyGoodBar() : m_memberA(0) , m_memberB(0) {} // bad CMyGoodBar() : m_memberA(0), m_memberB(0) {} // bad CMyGoodBar() : m_memberA(0), m_memberB(0) { } Tabs and spaces Format of every non-empty line of code should be: [<tabs>]text[<spaces>]text[<spaces>]... The following formatting options are not allowed: Space characters in the beginning of a row Tab characters in the right part of a row Recommended tab size is 2, although any setting can be used if the above rule is followed, and code should look good regardless. By setting the tab size to 2, the formatting tool will attempt to create a fixed block (spaces only) out of certain contexts, such as multi-line macro's, in an attempt to maintain right-alignment for the escape-newline sequence. However, more than 99% of the code should not be fixed-block since there is no right-alignment option that can be performed. Note: Don't use Convert tabs to spaces or similar options in your editor. Use Tab character to insert tabs in the code. If you follow this rule, then you can use any tab size without destroying existing format. Note that some old code still uses space characters instead of tabs and assumes that indentation is 2 to view such code properly, you can use Visual Studio's macros to switch between tabs size 2 and 4. Do not use space characters or multiple tabs to align expressions after wrapping lines. Preferably, let the formatting tool do this for you. Alternatively, you should use exactly one tab for indentation of wrapped lines if the tool cannot be used. Spaces in expressions Please ensure the below mentioned conditions are met: No space between function’s name and parentheses"(" No space before comma, semicolon, and parentheses Confidential. © 2009-2015 Crytek GmbH. All Rights Reserved. Page 3 of 23 Single space character before open and close brackets except while using double parentheses "))", and also after a comma Single space character before and after binary arithmetic operators (+, -, *, /, *, /, %, &, &&, |, ||, |=, ==, +=, etc.) and before unary operators (-, !, ~, etc.) Single space character before and after '?' and ':' in the conditional operator No spaces around < and > in template argument lists (see example below) Single space character between statement (if, while, for, switch, etc.) and the opening '(' Example if (a > b * c * (e - f)) { Grid<Sensor<float, double>> grid; const float r = ((a * 15.4f) / 3) + 2 + d * 4; DoSomething(&grid, a, c, e * f); ... } Long and complex expressions The below mentioned conditions should be followed while using long and complex expression in the code: Do not add multiple expressions, parameters or variables on the same line as it complicates both reading and code merging. It's always recomme nded to use a separate line for different expressions. Exceptions are possible. Do not use very complex expressions, especially as part of control statements. This may cause confusion for the user while decrypting the logic. Split complex expressions into multiple parts and use temporary const variables. It will make the code more readable and easier to debug. Use parentheses/brackets to improve readability of complex logical and arithmetical expressions. Understanding a complex braceless expression requires more time than understanding an expression with braces. Example // good int a = 3; int b = 5; // bad int a = 3, b = 5; Even though an expression is well-formed and non-ambiguous according to the C++ operator precedence rules, compilers will typically warn about omitted parentheses in certain expressions, even though they don't change the meaning of the expression. Therefore, prefer to introduce parentheses to clarify intentions when operators are "competing" inside one sub-expression: Two logical operators: a && b || c clarify to (a && b) || c Two bitwise operators: a | b & c clarify to a | (b & c) A shift and a compare: a >> b > c clarify to (a >> b) > c Any non-top-level assignment expression: if (a = b * c) clarify to if ((a = b * c)) Wrapping The formatting tool will maintain alignment for wrapped lines (By using spaces, it looks identical regardless of tab-space). This guideline can still be used for code where the code formatting tool cannot be used, but is generally obsolete since the code-base was reformatted. Use single tab indentation for wrapped lines. Do not align with ‘(‘, such alignment is hard to maintain in case of renaming functions and also sometimes it just looks like hanging in the middle of a page. If you think that the code looks bad after wrapping then use temporary variables to decrease sizes of the expressions. Confidential. © 2009-2015 Crytek GmbH. All Rights Reserved. Page 4 of 23 Example // good DoSomethingImportant( plumCount, “Alabama”, name, age, mass, validationPassed); // good DoSomethingImportant(plumCount,