2. Lexical Conventions
2.1 Character Sets
2.1.1 Do not use tab characters in source files
Tab width is not consistent across all editors or tools. Code indentation can be especially confusing when tabs and spaces are used interchangeably. This may easily happen where code is maintained using different editors. In string and character literals \t should be used in preference to a direct tab character.
#include <cstdint> void do_something(); void do_something_else(); void foo (int32_t i) { if (i) do_something (); do_something_else (); // @@- Non-Compliant: tab character used to indent this statement -@@ } void bar (int32_t i) { if (i) do_something (); do_something_else (); // this is what the code looks like with // tab width of 8 instead of 4 as above }
Indenting code only with spaces ensures that formatting is preserved when printing and across different editors or tools.
References
HIC++ v3.3 – 14.2
2.2 Trigraph Sequences
2.2.1 Do not use digraphs or trigraphs
Trigraphs are special three character sequences, beginning with two question marks and followed by one other character. They are translated into specific single characters, e.g. \ or ^. Digraphs are special two character sequences that are similarly translated. Be aware of trigraph and digraph character sequences and avoid them. It is possible to avoid such sequences arising accidentally by using spaces. In most modern environments there is no longer a need for trigraphs or digraphs, and their use will either result in hard to diagnose compiler errors or code that is difficult to maintain.
Trigraph | Equivalent | Digraph | Equivalent | |
??= | # | %:%: | ## | |
??( | [ | %: | # | |
??< | { | <: | [ | |
??) | ] | <% | { | |
??> | } | :> | ] | |
??/ | \ | %> | } | |
??’ | ˆ | |||
??! | | | |||
??- | ~ |
#include <cstdint> #include <iostream> #include <vector> void f1 () { // @@- Non-Compliant: here the ??/??/?? becomes \\?? after trigraph translation -@@ // std::cout << "Enter date ??/??/??"; } void f2 () { // @@- Non-Compliant: here the <::std::pair becomes [:std::pair -@@ // ::std::vector<::std::pair > vector_of_pairs; }
References
- HIC++ v3.3 – 14.18
2.3 Comments
2.3.1 Do not use the C comment delimiters /* … */
The scope of C++ comments is clearer: until the end of a logical source line (taking line splicing into account). Errors can result from nesting of C comments.
// @@- Non-Compliant example -@@ void foo (bool isLarge, bool isBright) { /* temporarily disable the code if (isLarge) { if (isBright) { /* if isLarge && isBright do something special */ } } */ // compilation error on unmatched '*/' }
References
HIC++ v3.3 – 14.1
2.3.2 Do not comment out code
Source code should always be under version control. Therefore keeping old code in comments is unnecessary. It can make browsing, searching, and refactoring the source code more difficult.
#include <memory> #include <cstdint> void foo_v1 () { int32_t * p = new int32_t; // ... delete p; } // use RAII for p void foo_v2 () { std::unique_ptr p (new int32_t ()); // ... // delete p; // @@- Non-Compliant -@@ }
In the above example, use of std::unique_ptr means that an explicit delete is no longer necessary. However, as the code was commented out rather than removed a reviewer will initially have to spend time confirming that delete is no longer necessary.
References
JSF AV C++ Rev C – 127
2.4 Identifiers
2.4.1 Ensure that each identifier is distinct from any other visible identifier
Similarity of identifiers impairs readability, can cause confusion and may lead to mistakes. Names should not differ only in case (foo/Foo) or in use of underscores (foobar/foo_bar). Additionally, certain combinations of characters look very similar:
O(o) | 0 | |
I(i) | l(L) 1 | |
S(s) | 5 | |
Z(z) | 2 | |
n(N) | h | |
B(b) | 8 |
rn(RN) m Identifiers that only differ in the above characters should also be avoided. This rule applies to pairs of identifiers that can be used in the same scope, i.e. one of them is visible with respect to the other. Note: This rule does not require that an identifier cannot be reused. See rule <hicpp ref=”basic.scope.no-hide”/>.
// t1.cc #include int32_t he1lo; // @@- Non-Compliant -@@ int32_t hel1o; // @@- Non-Compliant -@@ void FOO () { int32_t world; // @@+ Compliant: 'wor1d' is not visible +@@ } void BAR () { int32_t wor1d; // @@+ Compliant: 'world' is not visible +@@ } // t2.cc int32_t F00; // @@- Non-Compliant: 'FOO' is visible -@@
References
- HIC++ v3.3 – 8.3.4
- MISRA C++:2008 – 2-10-1
- Meyers Notes – Reference Binding Rules
2.5 Literals
2.5.1 Do not concatenate strings with different encoding prefixes
The C++ standard permits string literals with the following encoding prefixes: u, U, u8, L. A program that concatenates a pair of string literals with u8 and L prefixes is ill-formed. The result of the remaining prefix combinations are all implementation defined. For this reason, encoding prefixes should not be mixed.
auto hw (L"hello" u"world"); // @@- Non-Compliant -@@
References
HIC++ v3.3 – 6.5
2.5.2 Do not use octal constants (other than zero)
Octal literals are specified with a leading digit 0; therefore, literal 0 is technically an octal constant. Do not use any other octal literals, as based on unfamiliarity, this could be confusing and error-prone.
#include <cstdint> uint32_t v1 (10000); // decimal literal uint32_t v2 (00010); // @@- Non-Compliant: octal literal with value 8 -@@
References
- JSF AV C++ Rev C – 149
- MISRA C++:2008 – 2-13-2
2.5.3 Use nullptr for the null pointer constant
The 2011 C++ language standard introduced the nullptr keyword to denote a null pointer constant. The NULL macro and constant expressions with value 0 can be used in both pointer contexts and integral contexts. nullptr, however, is only valid for use in pointer contexts and so cannot be unexpectedly used as an integral value.
#include <cstdint> #include <cstddef> void f1(int32_t); // #1 void f1(int32_t*); // #2 int32_t * p = 0; // @@- Non-Compliant: avoid use of 0 as a null pointer constant -@@ int32_t i = 0; // @@+ Compliant: an integral expression is expected +@@ int32_t * t = nullptr; // @@+ Compliant: preferred way to specify a null pointer constant +@@ void f2() { f1(NULL); // @@- Non-Compliant: Calls #1 -@@ f1(nullptr); // @@+ Compliant: Calls #2 +@@ }
References
- HIC++ v3.3 – 14.16
- C++11 – 2.14.7