New coding guidelines: Difference between revisions
Jump to navigation
Jump to search
mNo edit summary |
m (define prefixes) |
||
Line 86: | Line 86: | ||
Both methods are '''OK'''. | Both methods are '''OK'''. | ||
</li> | |||
<li> | |||
When using the '''#define''' macro for addresses, you should use an appropriate prefix that indicates what the address represents. | |||
<syntaxhighlight lang="cpp"> | |||
#define FUNC_RemoveRef 0x4C4BB0 // Function address | |||
#define ARRAY_aCannons 0xC80740 // Array address | |||
#define STRUCT_CAESoundManager 0xB62CB0 // Struct address | |||
#define SIZE_CWaterCannon 0x3CC // Size of object (e.g., struct object) | |||
#define CLASSSIZE_WeaponInfo 112 // Class size | |||
#define NUM_CWaterCannon_Audio_Offset 0x32C // Number (e.g., offsets, integers, etc.) | |||
#define CLASS_CText 0xC1B340 // Class address | |||
#define VAR_CTempColModels_ModelPed1 0x968DF0 // Variable address (CColModel colModelPeds) | |||
</syntaxhighlight> | |||
</li> | </li> | ||
Revision as of 15:32, 19 June 2024
This page contains new and unofficial coding guidelines.
- Use const and constexpr wherever possible.
- Use the noexcept specifier whenever possible.
- Use nullptr instead of NULL when setting or returning a null pointer.
- Functions that only return a value should be placed in header files. For example, instead of:
// In .cpp file int GetGameSpeed() { return m_iGameSpeed; }
Do it in the header:
int GetGameSpeed() const { return m_iGameSpeed; }
- Use early-return to improve code readability. For example, instead of:
bool CStaticFunctionDefinitions::RespawnObject(CElement* pElement) { if (IS_OBJECT(pElement)) { CObject* pObject = static_cast<CObject*>(pElement); if (pObject) { pObject->Respawn(); return true; } } return false; }
It's clearer to do:
bool CStaticFunctionDefinitions::RespawnObject(CElement* pElement) { if (!IS_OBJECT(pElement)) return false; CObject* pObject = static_cast<CObject*>(pElement); if (!pObject) return false; pObject->Respawn(); return true; }
- Always strive to maintain code readability. If a type is lengthy to write, you can use auto to improve readability.
CDeatchmatchObject* pObject = static_cast<CDeathmatchObject*>(pEntity); // Can be auto* pObject = static_cast<CDeathmatchObject*>(pEntity);
- If you use addresses of values or functions, document what the address is with a comment or use a #define macro.
float CWeatherSA::GetWetRoads() const { return *(float*)0xC81308; // CWeather::WetRoads }
// In the header #define NUM_WETROADS 0xC81308 // In the .cpp float CWeatherSA::GetWetRoads() const { return *(float*)NUM_WETROADS; }
Both methods are OK.
-
When using the #define macro for addresses, you should use an appropriate prefix that indicates what the address represents.
#define FUNC_RemoveRef 0x4C4BB0 // Function address #define ARRAY_aCannons 0xC80740 // Array address #define STRUCT_CAESoundManager 0xB62CB0 // Struct address #define SIZE_CWaterCannon 0x3CC // Size of object (e.g., struct object) #define CLASSSIZE_WeaponInfo 112 // Class size #define NUM_CWaterCannon_Audio_Offset 0x32C // Number (e.g., offsets, integers, etc.) #define CLASS_CText 0xC1B340 // Class address #define VAR_CTempColModels_ModelPed1 0x968DF0 // Variable address (CColModel colModelPeds)
- For readability, if a loop or condition is short, omit curly braces. For example, instead of:
if (!bStillRunning) { StopMoving(); }
You can do:
if (!bStillRunning) StopMoving();
However, do not omit curly braces for larger blocks:
for (dont) for (do) for (this) ...
- Use range-based for loops when possible.
std::vector<int> vec; // Example std container // Bad: for (std::vector<int>::iterator it = vec.begin(); it != vec.end(); it++) // Good: for (const auto& v : vec) for (const int& v : vec) // In case of maps you can use structured binding: std::map<std::string, int> myMap; for (const auto& [k, v] : myMap) // There are situations where you must use old style loops, in this case use `auto` for (auto it = vec.begin(); it != vec.end(); it++)
- Define and call functions without arguments simply with empty parentheses.
// Bad void MyFunction(void); MyFunction(void); // Good void MyFunction(); MyFunction();
- When possible, use a logical condition for code readability. Instead of:
const CPositionRotationAnimation* CObject::GetMoveAnimation() { if (IsMoving()) { return m_pMoveAnimation; } else { return nullptr; } }
Do:
const CPositionRotationAnimation* CObject::GetMoveAnimation() { return (IsMoving() ? m_pMoveAnimation : nullptr); }
- Use lower camel case for variable names of types like custom structs and enums:
SSomeStruct valueOne; ESomeEnum m_valueTwo;
- Functions and classes use UpperCamelCase:
void UpperCamelCase(); class Vector;
- Use Hungarian notation for variable names when you can. It's not mandatory but helps with code readability.
float fValue; // Local variable unsigned char m_ucValue; // Class member variable char ms_cValue; // Class static member variable bool g_bCrashTwiceAnHour; // Global variable char* szUsername; // Zero-terminated string SString strUsername; // String CVector vecPosition; // 3D Vector
-
In C++, prefer using types from the std namespace provided by appropriate headers (such as <cstdint>, <cstddef>, etc.). This is recommended for several reasons:
- Namespace Safety: Types defined in these headers are encapsulated within the std namespace, which helps avoid naming conflicts with user-defined types or macros. This follows the C++ standard practice of minimizing global namespace pollution.
- Consistency and Readability: Using std:: types ensures consistency and improves code readability by making it clear that these types are part of the standard library.
- C++ Standard Compliance: The C++ standard (C++11 and later) includes headers like <cstdint> and <cstddef>, which provide standardized types:
- <cstdint> includes exact-width integer types such as 'std::uint32_t, std::int32_t, etc.
- <cstddef> includes types like std::size_t, std::ptrdiff_t, etc.
- Portability and Maintainability: Using these headers makes your code more portable across different compilers and platforms, as it guarantees that these types are defined in a standardized way. This is especially important in a C++ environment, where the focus is on maintainability and cross-platform compatibility.