1# C++ Coding Style and Conventions 2 3## General Philosophy 4 5Being an extensive and complicated language, there are often differences of 6opinions on "good" and "bad" C++ code. Bjarne Stroustrup has said "Within C++ is 7a smaller, simpler, safer language struggling to get out." We are striving to 8write in this variant of C++ and are therefore following the "C++ Core 9Guidelines" that Bjarne and Herb Sutter introduced at CppCon 2015. 10 11Beyond a set of rules that help codify "good" and "bad" C++, we have general 12principles that help us align the software we develop with the constraints 13within the problem domain being solved by OpenBMC. These are: 14 151. Code should be clear and concise. 162. Code should be written with modern practices. 173. Code should be performant. 18 19### Code should be clear and concise 20 21> Brevity is the soul of wit. 22 23It is important that code be optimized for the reviewer and maintainer and not 24for the writer. Solutions should avoid tricks that detract from the clarity of 25reviewing and understanding it. 26 27Modern practices allow C++ to be an expressive, but concise, language. We tend 28to favor solutions which succinctly represent the problem in as few lines as 29possible. 30 31When there is a conflict between clarity and conciseness, clarity should win 32out. 33 34### Code should be written with modern practices 35 36We strive to keep our code conforming to and utilizing of the latest in C++ 37standards. Today, that means all C++ code should be compiled using C++23 38compiler settings. As the C++26 standard is finalized and compilers support it, 39we will move to it as well. 40 41We also strive to keep the codebase up-to-date with the latest recommended 42practices by the language designers. This is reflected by the choice in 43following the C++ Core Guidelines. 44 45We finally desire to have computers do our thinking for us wherever possible. 46This means having Continuous Integration tests on each repository so that 47regressions are quickly identified prior to merge. It also means having as much 48of this document enforced by tools as possible by, for example, clang-format and 49clang-tidy. 50 51For those coming to the project from pre-C++11 environments we strongly 52recommend the book "Effective Modern C++" as a way to get up to speed on the 53differences between C++98/03 and C++11/14/17/20. 54 55### Code should be performant. 56 57OpenBMC targets embedded processors that typically have 32-64MB of flash and 58similar processing power of a typical smart-watch available in 2016. This means 59that there are times where we must limit library selection and/or coding 60techniques to compensate for this constraint. Due to the current technology, 61performance evaluation is done in order of { code size, cpu utilization, and 62memory size }. 63 64From a macro-optimization perspective, we expect all solutions to have an 65appropriate algorithmic complexity for the problem at hand. Therefore, an 66`O(n^3)` algorithm may be rejected even though it has good clarity when an 67`O(n*lg(n))` solution exists. 68 69## Global Guidelines and Practices 70 71Please follow the guidelines established by the C++ Core Guidelines (CCG). 72 73https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md 74 75[[Last reviewed revision is 53bc78f]] 76 77Exceptions: 78 79### Guideline Support Library (GSL) 80 81We do not currently utilize the Guideline Support Library provided by the CCG. 82Any recommendation within the CCG of GSL conventions may be ignored at this 83time. 84 85### Style recommendations 86 87The following are not followed: 88 89- NL.10 Avoid CamelCase 90- NL.17 Use K&R-derived layout 91 92## Library and Feature Specifics 93 94Additional recommendations within the OpenBMC project on specific language 95features or libraries. 96 97### Exceptions 98 99We do use exceptions as a basis for error handling within OpenBMC. 100 101### Boost 102 103Use of boost is allowed, under the following circumstances: 104 1051. Use is done as a header-only library. This allows unused functions and 106 methods to be removed by the compiler at link time, and avoids adding large 107 amounts of overhead and flash usage. 1082. Implementers should include the lowest level header required to solve the 109 problem at hand. This allows uses to be found and moved forward when new 110 standards are available, as well as reduce compile times, and decrease the 111 possibility of accidental use. (ie, #include <boost/container/flat_map.hpp> 112 not #include <boost/container.hpp>) 1133. The module used should not have an equivalent in the std namespace that meets 114 the same requirements for implementation or clarity: For example, std::chrono 115 should be preferred over boost::chrono. std::array over boost::array. 1164. Use does not conflict with any of the core tenants of this coding standard 117 (clarity, modern practices, or performance). 118 119### iostream 120 121The iostream conventions of using 'operator<<' contribute to an increased code 122size over printf-style operations, due to individual function calls for each 123appended value. We therefore do not use iostreams, or iostream-style APIs, for 124logging. 125 126There are cases when using an iostream utility (such as sstream) can result in 127clearer and similar-sized code. iostream may be used in those situations. 128 129## Coding Style 130 131Indentation, naming practices, etc. 132 133### General 134 135- Line length should be limited to 80 characters. 136- Indentation should be done with 4 space characters. 137- Files should use Unix-style newlines (\n). 138 139### Clang Formatting 140 141Individual OpenBMC repositories can use 142[clang-format](https://clang.llvm.org/docs/ClangFormat.html) if desired. The 143OpenBMC CI infrastructure will automatically verify the code formatting on code 144check-in if a .clang_format file is found within the root directory of the 145repository. This allows for automatic validation of code formatting upon 146check-in. 147 148If a custom configuration is desired, such as using different clang formatting 149for C and C++ files, a format-code.sh script can be created, which can for 150example use different .clang\* files as input depending on the file type. The 151format-code.sh script will be executed as part of CI if found in the root 152directory of the repository, and will check that there are no files that were 153modified after running it (same check as running clang). 154 155OpenBMC requires a clang-format of version 6.0 or greater. An example of how to 156run clang-format against all code in your repo can be found by referencing the 157[tool](https://github.com/openbmc/openbmc-build-scripts/blob/master/scripts/format-code.sh) 158used by CI. 159 160[Example .clang-format](https://www.github.com/openbmc/docs/blob/master/style/cpp/.clang-format) 161 162### Bracket style 163 164- Utilize 'Allman' style brackets. Brackets are on their own line at the same 165 indentation level as the statement that creates the scope. 166 167``` 168if (condition) 169{ 170 ... 171} 172``` 173 174``` 175void foo() 176{ 177 ... 178} 179``` 180 181- Even one line conditional and loop statements should have brackets. 182 183``` 184/// Wrong. 185if (condition) 186 do_something; 187 188/// Correct 189if (condition) 190{ 191 do_something; 192} 193``` 194 195### Indentation 196 197- Content within a namespace should be at the same indentation level as the 198 namespace itself. 199 200``` 201namespace foo 202{ 203 204content 205 206} 207``` 208 209- Content within a class / struct should be indented. 210 211``` 212class Foo 213{ 214 public: 215 Foo(); 216} 217``` 218 219- Content within a function / conditional / loop should be indented. 220 221``` 222void foo() 223{ 224 while (1) 225 { 226 if (bar()) 227 { 228 ... 229 } 230 } 231} 232``` 233 234- Switch / case statements should be indented. 235 236``` 237switch (foo) 238{ 239 case bar: 240 { 241 bar(); 242 break; 243 } 244 245 case baz: 246 { 247 baz(); 248 break; 249 } 250} 251``` 252 253- Labels should be indented so they appear at 1 level less than the current 254 indentation, rather than flush to the left. (This is not to say that goto and 255 labels are preferred or should be regularly used, but simply when they are 256 used, this is how they are to be used.) 257 258``` 259void foo() 260{ 261 if (bar) 262 { 263 do 264 { 265 if (baz) 266 { 267 goto exit; 268 } 269 270 } while(1); 271 272 exit: 273 cleanup(); 274 } 275} 276``` 277 278### Naming Conventions. 279 280- We generally abstain from any prefix or suffix on names. 281- Acronyms should be same-case throughout and follow the requirements as in 282 their appropriate section. 283 284``` 285/// Correct. 286SomeBMCType someBMCVariable = bmcFunction(); 287 288/// Wrong: type and variable are mixed-case, function isn't lowerCamelCase. 289SomeBmcType someBmcVariable = BMCFunction(); 290``` 291 292### Header Ordering 293 294Header inclusion order for a header file: 295 296``` 297local headers (e.g. "daemon_sys.hpp") 298c-libraries 299cpp-libraries (including openbmc libraries) 300``` 301 302Header inclusion order for a source file: 303 304``` 305source.hpp (if applicable) 306local headers 307c-libraries 308cpp-libraries 309``` 310 311All in alphabetically sorted order. 312 313#### Files 314 315- C++ headers should end in ".hpp". C headers should end in ".h". 316- C++ files should be named with lower_snake_case. 317 318#### Types 319 320- Prefer 'using' over 'typedef' for type aliases. 321- Structs, classes, enums, and typed template parameters should all be in 322 UpperCamelCase. 323- Prefer namespace scoping rather than long names with prefixes. 324- A single-word type alias within a struct / class may be lowercase to match STL 325 conventions (`using type = T`) while a multi-word type alias should be 326 UpperCamelCase (`using ArrayOfT = std::array<T, N>`). 327- Exception: A library API may use lower_snake_case to match conventions of the 328 STL or an underlying C library it is abstracting. Application APIs should all 329 be UpperCamelCase. 330- Exception: A for-convenience template type alias of a template class may end 331 in `_t` to match the conventions of the STL. 332 333``` 334template <typename T> 335class Foo 336{ 337 using type = std::decay_t<T>; 338}; 339 340template <typename T> using foo_t = Foo<T>::type; 341``` 342 343#### Variables 344 345- Variables should all be lowerCamelCase, including class members, with no 346 underscores. 347 348#### Functions 349 350- Functions should all be lowerCamelCase. 351- Exception: A library API may use lower_snake-case to match conventions of the 352 STL or an underlying C library it is abstracting. Application APIs should all 353 be lowerCamelCase. 354 355#### Constants 356 357- Constants and enum members should be named like variables in lowerCamelCase. 358 359#### Namespaces 360 361- Namespaces should be lower_snake_case. 362- Top-level namespace should be named based on the containing repository. 363- Favor a namespace called 'details' or 'internal' to indicate the equivalent of 364 a "private" namespace in a header file and anonymous namespaces in a C++ file. 365 366### Header Guards 367 368Prefer '#pragma once' header guard over '#ifndef'-style. 369 370### Additional Whitespace 371 372- Follow NL.18: Use C++-style declarator layout. 373 374``` 375foo(T& bar, const S* baz); /// Correct. 376foo(T &bar, const S *baz); /// Incorrect. 377``` 378 379- Follow NL.15: Use spaces sparingly. 380 381- Insert whitespace after a conditional and before parens. 382 383``` 384if (...) 385while (...) 386for (...) 387``` 388 389- Insert whitespace around binary operators for readability. 390 391``` 392foo((a-1)/b,c-2); /// Incorrect. 393foo((a - 1) / b, c - 2); /// Correct. 394``` 395 396- Do not insert whitespace around unary operators. 397 398``` 399a = * b; /// Incorrect. 400a = & b; /// Incorrect. 401a = b -> c; /// Incorrect. 402if (! a) /// Incorrect. 403``` 404 405- Do not insert whitespace inside parens or between a function call and 406 parameters. 407 408``` 409foo(x, y); /// Correct. 410foo ( x , y ); /// Incorrect. 411 412do (...) 413{ 414} while(0); /// 'while' here is structured like a function call. 415``` 416 417- Prefer line-breaks after operators to show continuation. 418 419``` 420if (this1 == that1 && 421 this2 == that2) /// Correct. 422 423if (this1 == that1 424 && this2 == that2) /// Incorrect. 425``` 426 427- Long lines should have continuation start at the same level as the parens or 428 all all items inside the parens should be at a 2-level indent. 429 430``` 431reallyLongFunctionCall(foo, 432 bar, 433 baz); // Correct. 434 435reallyLongFunctionCall( 436 foo, 437 bar, 438 baz); // Also correct. 439 440reallyLongFunctionCall( 441 foo, bar, baz); // Similarly correct. 442 443reallyLongFunctionCall(foo, 444 bar, 445 baz); // Incorrect. 446``` 447 448### Misc Guidelines. 449 450- Always use `size_t` or `ssize_t` for things that are sizes, counts, etc. You 451 need a strong rationale for using a sized type (ex. `uint8_t`) when a size_t 452 will do. 453 454- Use `uint8_t`, `int16_t`, `uint32_t`, `int64_t`, etc. for types where size is 455 important due to interactions with hardware or some externally defined API/ABI 456 (such as a system call or library interface). Do not use them, without good 457 reason, when such interaction is not involved; prefer size_t or int instead. 458