The author of the
Code, which is nice to read, shared his rules for writing good code, and in the end asked - “What other rules do you use? How to make the code more readable? I have at hand a document from one large English office for which I worked several years ago (Delcam International plc), which develops CAD / CAM systems and employs several hundred, if not thousands of programmers from different countries of the world.
Naturally, in order to organize effective work of such a number of programmers, especially with a different mentality, speaking different languages and thousands of kilometers from each other, rules were adopted within the company that a programmer must adhere to when writing code. The employee is given these rules when applying for a job, he must become familiar with them, and adhere to them. The rules concern a variety of areas, including even elementary code formatting and variable naming.
Some of them may seem obvious, some very controversial, some very useful. But in any case, this is the experience of a large company, and since they were introduced, it means there were reasons for this. I would be glad if you learn something useful for yourself, or implement some of them in your team and this will help you to work more effectively in a team.
')
A set of rules and guidelines for C ++ programming
at Delcam International plc
1
Introduction2
Basic rules and recommendations3
naming conventions4
Code Format and Text Formatting5
Comments6
Management Operators7
Files8
Preprocessor9
Classes10
Variables11
Functions12
Constructors / Destructors / Assignment Operators13
type casting14
Allocation and deletion of memory15
Friendly Classes and Friendly Functions16
Writing Portable CodeAppendix A: Code Format Examples
1 Introduction1. 1 ItemThis document is a set of rules and guidelines for C ++ programming at Delcam International plc. Our goal as a company is to write correct programs that are easy to support (both by the author and other programmers). Therefore, the goals of this standard are to make all Delcam code:- Easily maintained: easy to understand; as clear and simple as possible in practice; consistent in style. Reliable: free from errors; resistant to the introduction of errors during support; easy when testing.
- Combined: intended for transfer to various platforms and compilers; recyclable.
Since most of the writing is recommended for everyday practice, this document is primarily intended for programmers working in Delcam: Frequent references to home tools, software, practice, habits, etc. are not accepted.1. 2 Sources and targetsIn preparing this standard, several books and documents were used:EllemtelMats Henricson and Eric Nyquist, Programming
in C ++, Rules and Recommendations , (Ellemtel Telecommunication System
Laboratories)
ARMMargaret Ellis and Bjarne Stroustrup, The
Annotated C ++ Reference Manual, (Addison Wesley)PolicyEd Lambourne,
Delcam Software Development Policies ,
(Internal memo: Delcam International Plc.)
cppstdDavid Dunnington et al.,
The cppstd gripe file ,
(Internal document: Delcam International Plc.)
PhilosophyPaul Davies, David Dunnington,
Data Model programming
philosophy , (Internal document: Delcam International Plc.)
MaguireSteve Maguire,
Writing Solid CodeOuallineSteve Oualline,
C Elements of Style , (M & T
Publishing)
HobsSteve Hobbs,
Delcam Draft C Programming Standard ,
(Delcam International Plc.)
Ellemtel
is a great source: almost all the rules and recommendations overlap with this document. An invaluable source was also the cppstd gripe file, which gave a large amount of information. Thanks to all those who worked on cppstd, especially Paul Davies - who made the greatest contribution.This standard has little tutorial information. It is assumed that you are familiar with the basic constructs, syntax and use of C ++. Software design and development issues are also beyond the scope of this document. Beginners in the language are encouraged to refer to books for similar information. For starters, try The Complete C ++ Primer by Keith Weiskamp and Bryan Flamig (Academic Press). A good book on software engineering is Object Oriented Software Construction by Bertrand Meyer.
1. 3 Rules and recommendationsNon-compliance with the standard can be of two types: violation of the rule and not following the recommendation. Characteristics of the rule:Definition:An indication to follow. In the literal sense, the rule will be one of the goals (mentioned in the introduction).Exceptions:Only exceptions that are described in this document are allowed. Each rule documents all possible exceptions. New exceptions and changes may be negotiated and as a result reflected in this document.Compulsion:The commission accepting the code must reject it if it violates the rules.Control:The code may be subjected to automatic tests and / or checks.Characteristics of the recommendation:Definition:Advice that must be followed if you do not have a good reason for not doing so. Disagreement with the recommendation is not a good reason. Recommendations are formulated from the fact that in the future they tend to go into the rules.Exceptions:Major exceptions are often documented along with separate recommendations. If you are not sure if you have the correct reason, discuss this issue with the administrator of the standard.Compulsion:Be prepared to defend breaking the recommendation.Control:The code may be subjected to automatic tests and / or checks.If you think that the rule or recommendation is incorrect, it is better to try to change them than to ignore. This statement is emphasized by Policy. 7No need to reformat or rewrite old code. It is welcomed (but not obligated) to make changes that are consistent with the standard when you need to modify the code during the support. You can save the formatting method used in the old code when expanding it, but when making changes follow the rules and recommendations that are not related to formatting.1. 4 Organization The authors of this document are people (despite rumors saying otherwise) and therefore it is not perfect. The document is designed to be developed and will improve over time.To facilitate the evolution of the standard, document versioning is managed by a gripe system with the item name cppstd (C-Plus-Plus-STandarD). Type `gripe -doc 'to learn gripe and` gripe cppstd -help' for more information on cppstd. Comments, questions, suggestions, etc., should be recorded via gripe.Rules and recommendations are given by keywords, not numbers, in order not to deal with obsolete numbers.- Previous keyword
r- is the rule. - Previous keyword
s- - recommendation.
Each rule and recommendation has a 'compressed form' and a block of additional text. Additional text may contain additional clauses, reservations and / or exceptions that are as important as the 'compressed form' and should not be ignored.
2 Basic rules and recommendations2. 1 Policy Guidesr-gen-golden: Follow the Golden Rule.Every time a rule is violated, this should be clearly documented. The violation must be sanctioned by people who support the standard and it will be modified as a result.s-gen-dupl: Do not duplicate the code.Code duplication is considered a deadly sin. Highlight the code common to the two functions in a separate
function. Use existing class libraries when possible. In particular, two standard class libraries are of interest.
Delcam: utils.dev, which contains software tools that are not in the C ++ standard (for example, the abstract class of strings) and contain e
r.dev, which contains the basic abstract data types for storing objects.s-gen-reuse: Develop reusable code.When possible, software should be developed in the context of a library of related tools, with a well-defined, clearly written interface. Libraries should be linked in a clear, documented, hierarchical way.s-gen-simple: Keep the code simple.Write code for the 'average' programmer. The 'smart' code is hard to understand, and therefore less
suitable for reuse and difficult to maintain. Always lean towards simplicity and readability. In the literature, this is known as the kiss ("keep it simple, stupid") principle.s-gen-test: Write the code under test and test it.Create a solid testing subsystem and use them later. Write and test small pieces of code. Use the debugger more often to go step by step through your code, just wait until you get an error. Correct errors as soon as they are found, eliminate the cause, not the symptom.2. 2 Basic Writing Guides
of programss-gen-mc: Place platform-dependent code in one place.Place the platform dependent code in a special file. In Delcam, this is apsl.dev/apsl/machine.h.s-gen-comp: If the code needs to be changed due to an error in some compiler, comment
code to point this out, giving details about the compiler.Report a compiler error using 'gripe cppbug' so that we can take action to correct it.s-gen-opt: Optimize code only when needed.Optimize the code only if you know that you have performance problems. If your program is too slow, use groff ++ or an equivalent tool to determine the exact cause of the problem before starting the optimization.s-gen-warn: Allow all compiler warnings.Activate compiler warnings, if possible, to localize errors and reduce the amount of code that needs to be rewritten for each new version of the compiler (because today's warnings often become errors tomorrow).Example: using the Cfront compiler, compile with the + w flag to eliminate as much as possible
warnings.s-gen-asser t: Use assertion to verify your code.Assertion is described in Maguire. The implementation of assertion in Delcam is in utils.dev/utils/ut_assert.h and is described in d0170400.Additional help on finding bugs and testing procedures can be found in Maguire.
3 naming conventionsChoosing meaningful names is an important part in writing easy-to-read code. Consistent use of naming conventions improves the readability of the code, allowing a person to quickly understand the structure of the program. Another requirement is to establish order to minimize the risk of naming conflicts. This section describes naming conventions designed to promote readability, consistency, and support large-scale development. Hereinafter, the type is a class, enum or typedef.3. 1 Library PrefixesAll files, their contents (classes, functions, etc.) belong to some library.r-nam-libpx: Assign a prefix to each library.Each library must be associated with a unique two or three letter prefix for this library. Prefix letters must be lowercase.r-nam-glob: Use the library prefix for all global names.If an object within a library is part of a global namespace, its name must begin with the library prefix.The rules that tell how a name is composed of a prefix are given in the next section. Responsibility of the author or support person is to ensure the absence of name conflicts in the library. The prefix will warn (hopefully!) Name conflicts outside the library.3. 2 Names of types, variables, functions, macrosThe following rules explain how to name various objects. Examples are given under the assumption that the library prefix is z z.
r-nam-type: Type names begin with a capital letter.Type names are written in small letters, each new word begins with a capital letter. They should not contain underscores. Names should be preceded by a prefix written in small letters. Nested classes / enumerated types (enum) are rare and their use is not advised in view of possible problems with the SGI and HP compilers. If they are, however, used, their names should be chosen, however, as for global class names due to problems with the compiler.Example: class zzMyClass {
...r-nam-var: Follow the prescribed method for naming variables, local constants, and function arguments.The names of variables, local constants and function arguments are written in small letters, with words separated by a single underscore. Their prefixes should be as follows:Example: const int local_const; Example:
int local_var; Example: int zz_global_var; Example: int m_member_var; Example:
static int s_static_member_var; // (recommended)Example: void f (int a_argument);
// (recommended)r-nam-glcon: The names of global constants and enum constants (enum) are capitalized.Use one underscore to separate words. The prefix must be typed in lowercase. Example:
const int zzGLOBAL_CONST;Example: enum zzKind {zzONE_KIND,
..r-nam-func: Function names are written in small letters.Use one underscore to separate words. Global functions are prefixed by small letters followed by an underscore. Class member functions do not require a prefix. Exception: r-nam-farg.Exception: r-nam-fclass.r-nam-farg: If the argument of the type containing the prefix is passed to the global function, it is not necessary to add the prefix to the function name.The risk of a name conflict in this case is very small. This allows the programmer to write functions that are closely related to the class, without the syntactic clutter of the name with the prefix. For example, you might want to declare a member function of the class 'int zzClass :: f () const' and a friendly function 'int f (const zzClass &)', which simplify the syntax when an instance participates in the evaluation of an expression:
'i = (a + b) .f ()' will be replaced by 'i = f (a + b)'. Example: void zzClass :: member (); Example:
void zz_global_func ();Example: void global_func (const
zzClass &);r-nam-fclass: If the type name is part of the function name, then the type name must be written in the same way as in the type definition (including capital letters).If the type is declared in the same library as the function, it is not necessary to add an additional library prefix to the function name, since it already exists in the class name and also as in r-nam-farg the risk of a name conflict with another library is very small. Example: void test_zzClass (); Example: void zzClass :: member ();
Example: void zz_global_func ();Example: void global_func (const
zzClass &);s-nam-funcstd: Use
standard names of member functions of a class, if they exist.Some class member functions
are common to many classes, and their names are standardized: see
section 12.2.1. If the access function sets an attribute of class <attrib> of type <zzAttrib> it
must have a void set_ <attrib> prototype (const <zzAttrib> &) ;.
If the access function returns an attribute, it must have a prototype
const <zzAttrib> & <attrib> () const or <zzAttrib> <attrib> ()
const if the attribute has an assignment statement and a copy constructor
(see section 12.3).r-nam-macro: Macro names are capitalized.Use one underscore to separate words. The library prefix must be entered in large letters, followed by an underscore. See also r-def-minusd §8. Exception: macros involved in preventing the inclusion of header files should be described as in r-cpp-ifdef §8.2.Exception: the macro definitions 'declarations' and 'implementations' associated with the main classes can be called arbitrarily.Example: #define ZZ_LIB_MACRO
0
r-nam-und: don't start
underscore names.Naming conventions exclude names of types or variables beginning with an underscore. The use of two underscores in identifiers is reserved according to the ANSI-C standard for internal compiler use.Names that begin with a single underscore are often used by standard library functions (ex. '_Main' and '_exit').r-nam-twound: Do not use two underscores in a row.Appendix B provides a generic table of all naming conventions.3. 2 Style Recommendationss-nam-abbrev: Use abbreviations less often.Cut words only when the cut is widely known (either within the company or in the world).
For example: 'DDX' is short for Delcam; the loop variable 'i' is a 'standard' programmer shortcut and is much better than 'array_index'. Difficult names are considered bad.s-nam-length: Do not overdo it with the length of the name.Do not make the names too long because some environments impose restrictions on the number of characters to be recognized. For example, the unix 'ar' command truncates filenames longer than 15 characters.s-nam-desc: Use simple, descriptive names.The name of a variable should talk about its use. The best if the variable name contains one, two words. If there are three, then this already attracts attention, and if there are four, then the name may be difficult to read. When creating a name from two words, place the most important word first.s-nam-dif: Names must be significantly different.Do not use variable names differing only by one, two characters. Do not use type names that differ only in case of letters. At the same time, use similar names for variables that perform similar functions.s-nam-std: Avoid using the names used in the standard library.This is recommended even for local objects, because the macro definitions are not limited by the rules (the problem will be alleviated if the objects in the standard library have prefixes). This is a recommendation, not a rule, because, sometimes, very common (and therefore widely used) words (for example, 'index') are used in the standard library.3. 4 File NamesThere are four types of files:- Header files contain type definitions, function prototypes, etc. Source files contain class implementations, etc. Inline files contain inline functions.
- Outline files ensure that non-inline versions of inline functions are available for debugging purposes.
The file naming rules are listed below.r-nam-clfile: Files containing class implementations must have the same name as the class.The file name must be in the same case as the class name. This also applies to the main classes. The rule applies to header, inline and source files.r-nam-utfile: A file that implements a set of utilities must have a lowercase name, preceded by the library prefix.The prefix must be separated from the name by a single underscore. The rule applies to header, inline and source files.r-nam-enum: A header file containing only one enumeration (enum) may have the same name as the enumeration.r-nam-ext: File extensions: header .h, source text / outline .c, inline .i.Ellemtel prefers '.hh', '.cc' and '.icc', reserving '.h' and '.c' for files that can be accepted by both C and C ++ compilers. Since all Delcam code, according to the rules, must be compiled by C ++, we do not make such differences.r-nam-outline: The outline file has the same name as the corresponding header, with the 'I' added (before the file extension).r-nam-split: If the source file becomes large and you need to split it, the name of each new file is the name of the old file, followed by an underscore, and then a word in lowercase.For example, if the zzClass.c file contains the zzClass :: member () member function, which is implemented in a separate file, the file might be called zzClass_member.c.Examples: zzClass.c: source file that implements the zzClass class. zz_utils.h: utilities header file. zz_utils.i: implementation of inline functions defined in zz_utils.h.zzClassI.c: outline version of the built-in (inline) functions defined in zzClass.h.
4 Code Format and Text FormattingThis section defines how the code should look.4. 1 Common Code Formatr-fmt-brace: Use the only correct bracketing style.The brackets must be arranged according to the K & R short form: the opening bracket is located at the end of the line immediately after the preceding code. The closing bracket is located on a separate line, in the column corresponding to the first non-blank character in the line where the opening bracket is located. The code between the two brackets is indented.Example:if (function_returns_true ()) {
execute_this_code ();
}
Exception: the opening bracket ({) of the function must be on a separate line.Exception: function argument can occupy a separate line.r-fmt-lines: The length of the line should not exceed 79 characters.This limit was chosen because the standard 'emacs' setting used by us creates a window where lines of greater length collapse. In addition, 80x24 (80x25) is a frequently found window size that comes from old terminals, and folded lines are harder to read.r-fmt-indent: The indent is two spaces.Retreat one level for each new level of logic.Exception: if-else sequences are easier to read when the element is aligned - see r-if-elseif.r-fmt-tabs: Do not use tabs.They make it difficult to maintain indents while maintaining the code. Avoid using other exotic characters.s-fmt-sep: Do not use unnecessary delimiters.Example: do not use additional commas after the last value in enums ('strict' compilers will produce errors, for example IBM).4. 2 Operatorss-fmt-long: Avoid using very long statements.Instead, use a few shorter statements.s-fmt-stat: Put each statement on a separate line.If you do not do this, you must be sure that the clarity of the program from this will improve.s-fmt-col: When arranging several operators on the same line, group the operators into columns.s-fmt-split: Breaking the line, retreat another level.If you need to split a line into several lines, indent all lines except the first one for one additional level. Exception: see s-fmt-splitexpr.Exception: management structures are broken down as described in the corresponding section (§6).4. 3 Expressionss-fmt-splitexpr: When breaking an expression, the subexpressions of the same logical level must be aligned vertically.Avoid breaking the expression where the nesting level is high. Put arithmetic and logical operators at the end of the line, not at the beginning of the next. So much easier to follow the logic of a long expression.Example:result = (((x1 + 1) * (x1 + 1)) -
((y1 + 1) * (y1 + 1)));
Example: an assignment expression can be broken like this:result = a_long * hypotenuse +
2.0 * cos (alpha);
When aligning a broken expression, either neither or both subexpressions must be bracketed.Example:if ((a && b) ||
c) {// Do not do thisIt is better to write this:if ((a && b) ||
©) {// Much betters-fmt-prec: Use parentheses frequently to make the priority of operations clear.Do not look for priority in a table if you don’t remember it: use parentheses instead. If you cannot remember the priority of the operation, then there is a high probability that the one who reads your code will not remember it either. As a rule, the priority between operations +, / and +, -; use brackets in all other cases.4. 4 SpacesThese recommendations apply to spaces inside the line, not to those used for indentation.- Never use more than one space.
(eg, a search on 'class <class>' should find the definition of the class <clas s>). - Never use spaces between a pointer variable and '[' (for example, a search on 'array [' should find references to array elements). Never use spaces between the function name and '(' (eg, search on 'func (' should find all function calls). Always enter a space between '(' and the control operator (eg use 'while (x)', and not 'while (x)'). Always enter a space before '{' and '}' (except when they are at the beginning of a line).
- Always enter a space after the '{' and '}' (except when they are at the end of the line).
- Never enter a space before the characters ',;)]'.
- Never enter a space after the '(' or ']'. It is recommended to put spaces after commas in definitions and expressions, but they are not necessary between arguments in the function call. It is recommended to put spaces around the?: '. It is recommended to put spaces around the assignment operator. Not enter spaces between unary operations and operands. Do not use spaces around '::', '.' or '->'. Do not enter spaces after the keyword 'operator'.
- Except for the recommendations above, spaces are optional around operators.
s-fmt-space: Follow the guidelines for using spaces.
5 CommentsThis section explains how to write comments. .