Software Engineering Fundamentals - Personal Projects - Code Style Specification


Code style guidelines

Excerpted from the Google C++ style guide , and tried to be the norm, but not exactly the same.


1. Naming Conventions

1.1 File naming

General The
file names are all lowercase and can be underlined _, but not dashes -.
Description
Examples of acceptable file names:

  • input_ouput.cpp
  • sudoku.cpp
  • stdafx.h

ends with C++ files and .cppends with header files .h.

1.2 Type naming

General
The first letter of each word in the type name is capitalized, without underscores.
Description
All type names—classes, structures, type definitions ( typedef), enums, type template parameters—use the same convention, starting with an uppercase letter, capitalizing the first letter of each word, and not using underscores. E.g:

// 类和结构体
class Sudoku {...};
class Input {..};
struct SonNode {..};

// 类型定义
typedef hash_map<char *, string> NameMap;

// using 别名
using NameMap = hash_map<char *, string>;

// 枚举
enum Today {..};

1.3 Variable naming

General
Variables (including function parameters) and data member names are always lowercase, and words are connected with underscores. Member variables of a class end with an underscore, but not of a structure. Such as: a_local_variable, a_struct_data_member, a_class_data_member_.
Description

1.3.1 Common variable naming

E.g:

int num_table; // 好 - 用下划线
int numtable;  // 中 - 全小写
int numTable;  // 差 - 混合大小写

1.3.2 Class data members

Whether static or non-static, class data members can be the same as ordinary variables, but with an underscore at the end of the name.

class TableInfo 
{
    ..
private:
    string table_name_;  // 好 - 后加下划线.
    string tablename_;   // 中.
    static Pool<TableInfo>* pool_;  // 好.
};

1.3.3 Structure variables

Whether static or non-static, structure data members can be the same as ordinary variables, but without the underscore like a class.

struct UrlTableProperties 
{
    string name;
    int num_entries;
    static Pool<UrlTableProperties>* pool;
};

1.4 Constant naming

Overview
Variables declared as constexprOR const, or whose value remains the same during program execution, are named starting with a "k" in mixed case. For example:

const int kDaysInAWeek = 7;

Note
All variables with static storage type (such as static variables or global variables) should be named this way. For variables of other storage types, such as automatic variables, this rule is optional. If this rule is not used, the normal variable naming rules are followed.

1.5 Function Naming

General
functions use mixed case, member function first letter is lowercase: MyExcitingFunction(), MyExcitingMethod(), myExcitingMethod().
Description
In general, the first letter of each word in a function name is capitalized (ie "CamelCase" or "Pascal Case") without underscores.

1.6 Namespace naming

Overview
Namespaces are named with lowercase letters. The name of the top-level namespace depends on the project name. Care should be taken to avoid conflicts between nested namespace names and common top-level namespace names.
The name of the top-level namespace should be the project name or the name of the team to which the code in that namespace belongs. Code in a namespace should be placed in a folder or subfolder that matches the name of the namespace.
Note that the same rules for not using abbreviations as names apply to namespaces. Code in a namespace rarely needs to refer to the name of the namespace, so there is no need to use abbreviations in namespaces.
To avoid name collisions between nested namespaces and common top-level namespaces. It is entirely possible for a conflict between namespaces to cause compilation to fail due to name lookup rules. In particular, don't create nested stdnamespaces. It is recommended to use more unique project identifiers ( websearch::index, websearch::index_util) rather than common, highly conflict-prone names (eg websearch::util).
For internalnamespaces, beware internalof conflicts between code added to the same namespace (as internal maintainers are usually from the same team, conflicts are often possible). In this case, use the filename to make the internal name unique (for example frobber.h, use websearch::index::frobber_internal.

1.7 Enumeration naming

General
Enumerations should be named the same as constants or macros : kEnumNameor ENUM_NAME.

1.8 Macro Naming

General
All caps, use underscore: MY_MACRO_THAT_SCARES_SMALL_CHILDREN.


2. Notes

2.1 File Comments

Overview
File comments describe the contents of the file. If a file only declares, or implements, or tests an object, and the object has been commented in detail at its declaration, then there is no need to add a file comment. All files other than this require file comments.

2.2 Class annotations

General
Each class definition is accompanied by a comment describing the function and usage of the class, unless its function is obvious.

// Iterates over the contents of a GargantuanTable.
// Example:
//    GargantuanTableIterator* iter = table->NewIterator();
//    for (iter->Seek("foo"); !iter->done(); iter->Next()) {
//      process(iter->key(), iter->value());
//    }
//    delete iter;

class GargantuanTableIterator 
{
    //..
};

Description
Class annotations should provide the reader with enough information to understand how and when to use the class, and should remind the reader of the factors to consider when using the class correctly. If the class has any synchronization prerequisites, please document it. If instances of this class can be accessed by multiple threads, pay special attention to the rules and constants used in the documentation describing the multi-threaded environment.
If you want to demonstrate the basic or common usage of this class with a small piece of code, it is also very suitable to put it in a class comment.
If the class declaration and definition are separated (for example, in .hand .cppfile respectively), then comments describing the usage of the class should be placed with the interface definition, and comments describing the operation and implementation of the class should be placed with the implementation.

2.3 Function Comments

Overview
Comments at function declaration describe function functionality; comments at definition describe function implementation.
illustrate

2.3.1 Function declaration

Basically every function declaration should be preceded by a comment describing the function and purpose of the function. These annotations should only be omitted if the function of the function is simple and obvious (for example, simple getter and setter functions). Comments are declarative ("Opens the file") rather than imperative ("Open the file"); comments are only meant to describe the function, not to dictate what the function does. Usually, comments don't describe how the function works. That's a function definition part thing.

The content of the comment at the function declaration:

  • function input and output
  • For class member functions: whether the object needs to keep reference parameters during the function call, and whether these parameters will be released
  • Does the function allocate space that must be freed by the caller
  • Can the parameter be a null pointer
  • Are there performance risks in the use of functions?
  • If a function is reentrant, what are its synchronization prerequisites?

An example is as follows:

//* Returns an iterator for this table.  It is the client's
// responsibility to delete the iterator when it is done with it,
// and it must not use the iterator once the GargantuanTable object
// on which the iterator was created has been deleted.
//
// The iterator is initially positioned at the beginning of the table.
//
// This method is equivalent to:
//    Iterator* iter = table->NewIterator();
//    iter->Seek("");
//    return iter;
// If you are going to immediately seek to another place in the
// returned iterator, it will be faster to use NewIterator()
// and avoid the extra seek.
Iterator* GetIterator() const;

But also avoid being wordy or stating the obvious. The following comment does not need to add "else return false", because it is already implied:

// Returns true if the table cannot hold any more entries.
//
bool IsTableFull();

When annotating function overloading, the focus of the comment should be on the overloaded part of the function, rather than simply repeating the comment of the overloaded function. In most cases, function overloading does not require additional documentation, so comments are not necessary.
When annotating constructors/destructors, remember that the person reading the code knows what the constructor/destructor does, so comments like "destroy this object" are meaningless. What you should note is to note what the constructor does with the parameters (for example, whether to take ownership of the pointer) and what the destructor cleans up. If it's all irrelevant, just omit the comment. It is normal to have no comments before the destructor.

2.3.2 Function Definition

If the function is implemented in a clever way, then an explanatory comment should be added to the function definition. For example, the programming techniques you used, the general steps to implement it, or an explanation of why it was implemented in this way. For example, you can show why the first half of the function needs to be locked and the second half does not.
Do not .hcopy comments directly from function declarations in files or elsewhere. It's fine to briefly restate what the function does, but the focus of comments should be on how to do it.

2.4 Variable Comments

Overview
Often the variable name itself is a good enough description of the variable's purpose. In some cases, additional annotations are also required.
illustrate

2.4.1 Class data members

Each class data member (also called instance variable or member variable) should be annotated to describe its purpose. If there are non-variable parameters (such as special values, relationships between data members, life cycle, etc.) that cannot be clearly expressed by the type and variable name, they should be commented. However, if the variable type and variable name are sufficient to describe a variable, then there is no need to add a comment.
In particular, if the variable can accept NULLor -1equal the guard value, it shall be stated. for example:

private:
// Used to bounds-check table accesses. -1 means
// that we don't yet know how many entries the table has.
int num_total_entries_;

2.4.2 Global variables

Like data members, all global variables are also annotated to explain their meaning and purpose, and why they are global variables. for example:

// The total number of tests cases that we run through in this regression test.
const int kNumTestCases = 6;

2.5 Implementation Notes

Overview
Comment out the subtle, obscure, interesting, and important places in your code.
illustrate

2.5.1 Comments before code

Add comments before clever or complex code snippets. for example:

// Divide result by two, taking into account that x
// contains the carry from the add.
for (int i = 0; i < result->size(); i++) 
{
    x = (x << 8) + (*result)[i];
    (*result)[i] = x >> 1;
    x &= 1;
}

2.5.2 Line Comments

More obscure places to add comments at the end of the line. Comment with two spaces at the end of the line. for example:

// If we have enough memory, mmap the data portion too.
mmap_budget = max<int64>(0, mmap_budget - index_->length());
if (mmap_budget >= data_size_ && !MmapData(mmap_chunk_bytes, mlock))
    return;  // Error already logged.

Note that two paragraphs of comments are used to describe the function of this code, and the error has been logged when the function returns.
If you need multiple lines of comments in a row, you can align them for better readability:

DoSomething();                  // Comment here so the comments line up.
DoSomethingElseThatIsLonger();  // Two spaces between the code and the comment.
{ // One space before comment when opening a new scope is allowed,
// thus the comment lines up with the following comments and code.
    DoSomethingElse();  // Two spaces before line comments normally.
}
std::vector<string> list{
                    // Comments in braced lists describe the next element...
                    "First item",
                    // .. and should be aligned appropriately.
"Second item"};
DoSomething(); /* For trailing block comments, one space is fine. */

2.5.3 Function parameter comments

If the meaning of the function parameters is not obvious, consider making up for it in the following ways:

  • If the parameter is a literal constant, and the constant is used in multiple function calls to infer them to agree, you should use a constant name to make this convention more obvious and to ensure that this convention is not broken .
  • Consider changing the signature of the function so that a boolparameter of a type becomes a enumtype, so that the value of the parameter expresses its meaning.
  • If a function has multiple configuration options, you might consider defining a class or struct to hold all the options, and pass in an instance of the class or struct. There are many advantages to this approach, for example such options can be referenced by variable names at the call site, which makes their meaning clear. It also reduces the number of function parameters, making function calls easier to read and write. Other than that, in this way, if you use other options, you don't need to make changes to the call site.
  • Replace large and complex nested expressions with named variables.
  • As a last resort, consider using annotations to clarify the meaning of parameters at the call site.

For example, compare the following cases:

// What are these arguments?
const DecimalNumber product = CalculateProduct(values, 7, false, nullptr);

and

ProductOptions options;
options.set_precision_decimals(7);
options.set_use_cache(ProductOptions::kDontUseCache);
const DecimalNumber product =
    CalculateProduct(values, options, /*completion_callback=*/nullptr);

Which one is clearer at a glance.

2.5.4 Impermissible Behavior

Don't describe obvious phenomena, and never translate code in natural language as comments unless the behavior of the code is not obvious even to a reader with a deep understanding of C++. Assume that the person reading the code is better at C++ than you, even though he/she may not know what you mean.
The comments you provide should explain why the code is doing it and the purpose of the code , or preferably make the code self-documenting .
Compare annotations like this:

// Find the element in the vector.   差: 这太明显了!
auto iter = std::find(v.begin(), v.end(), element);
if (iter != v.end()) {
    Process(element);
}

and an annotation like this:

// Process "element" unless it was already processed.
auto iter = std::find(v.begin(), v.end(), element);
if (iter != v.end()) {
    Process(element);
}

Self-documenting code doesn't need comments at all. The comments in the above example are unnecessary for the following code:

if (!IsAlreadyProcessed(element)) {
    Process(element);
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325725959&siteId=291194637