基本原则:好的代码,能够减少 "别人" 理解它的时间。 "别人" 不仅指的是 其他人,也可能是 以后的自己
1 代码应易理解
1.1 符合习惯
下面两种形式等效,但方式2 更符合编码习惯,容易理解
// 方式 1 Node* node = list->head; if (node == NULL) return; while(node->next != NULL) { Print(node->data) node = node->next; } if(node != NULL) Print(node->data); // 方式 2 for (Node* node = list->head; node != NULL; node = node->next) Print(node->data);
1.2 少且易懂
1) 少 + 易懂
// 多 - if 语句 if(exponent >= 0) { return mantissa * (1 << exponent); } else { return mantissa / (1 << -exponent); } // 少 - 条件运算符 return exponent >= 0 ? mantissa * (1 << exponent) : mantissa / (1 << -exponent);
2) 少 + 不易懂
// 少 - 不易理解 assert ((!(bucket = FindBucket(key))) || !bucket->IsOccupied()); // 多 - 易理解 bucket = FindBucket(key); if(bucket != NULL) asset(!bucket->IsOccupied());
2 封装信息到名字
2.1 命名要贴切
2.1.1 使用特有的词
BinaryTree 类中的 Size() 不如 Height()、NumNodes() 或 MemoryBytes() 更明确;Thread 类中 通常是 Kill(),而不是 Stop(),且 Pause() 和 Resume() 成对出现
常用词语的替代词,如下:
// send = deliver, dispatch, announce, distribute, route // find = search, extract, locate, recover // start = launch, create, begin, open // make = create, set up, build, generate, compose, add, new
2.1.2 避免通用名
retval 是 “平方和”,不如 sum_squares 合适
var euclidean_norm = function (v) { var retval = 0.0; for (var i = 0; i < v.length; i += 1) retval += v[i] * v[i]; return Math.sqrt(retval); };
如下 tmp 较为合适
if (right < left) { tmp = right; right = left; left = tmp; }
但下例的 tmp 就不如 tmp_file 更明确
tmp_file = tempfile.NamedTemporaryFile() ... SaveDate(tmp_file, ...)
i, j, k 易混淆,不如 clubs_i, members_i, users_i 方便,或简化为 ci, mi, ui
for (int i = 0; i < clubs.size(); i++) for (int j = 0; j < clubs[i].members.size(); j++) for (int k = 0; k < users.size(); k++) if (clubs[i].members[k] == users[j]) cout << "user[" << j << "] is in club[" << i << "]" << endl;
2.1.3 使用具体的名
谷歌早期的 C++编码规范,为了避免编译器自动生成拷贝构造函数和赋值算子,定义了如下宏:
#define DISALLOW_EVIL_CONSTRUCTORS(ClassName) \ ClassName(const ClassName&); \ void operator=(const ClassName&);
这个名字不如后来的 DISALLOW_COPY_AND_ASSIGN(ClassName) 贴切
实际上,C++11 有了 delete 关键字,无须使用该宏了,参见 C++11 之 delete 和 default
2.2 附加额外信息
2.2.1 类型
某些变量,附加额外的信息可以更好的理解,如,一个16进制的变量,命名为 hex_id 比 id 更贴切
// Example: "af84ef845cd8" string hex_id;
2.2.2 单位
如下 getTime() 返回值的单位是 ms 而不是 s,可将 _ms 作为后缀加到变量的后面,则会使代码变得更为清晰
var start_ms = (new Date()).getTime(); // top of the page ... var elapsed_ms = (new Date()).getTime() - start_ms; // bottom of the page document.writeln("Load time was: " + elapsed_ms / 1000 + " seconds");
除了时间,还有别的单位:
// 带单位的函数参数 Start (int delay_secs) CreateCache (int size_mb) ThrottleDownload (float limit_kbps) Rotate (float angle_cw)
2.2.3 其它属性
一些有关安全的变量命名,也常需要一些额外的信息
// A password is in "plaintext" and should be encrypted before further processing std::string plaintext_password; // Byte of html have been converted to UTF-8 std::string html_utf8; // Incoming data has been "url encoded" std::string data_urlenc;
2.3 格式要求
2.3.1 作用域和缩写
- 长名长域,短名短域:变量 m 并没有封装任何信息,但是因为只在 if 作用域内有效,所以并不对妨碍代码的理解
- 善用缩写:当变量名实在太长,可考虑缩写,但要注意团队中的新人,也能理解缩写的含义。如,evaluation 常缩写为 eval,document -> doc,string -> str
- 去掉无用词:ToString() 优于 ConvertToString(),ServeLoop() 比 DoServeLoop() 简洁
if (debug) { map<string,int> m; LookUpNamesNumbers(&m); Print(m); }
2.3.2 下划线和大写
谷歌 C++ 编码规范中:
- 类名一般是各个首字母大写,类成员函数名也是如此;
- 类成员变量名后都带有下划线 "_";
- 常量命名为 kConstantName,和 #define MACRO_NAME 宏区分
static const int kMaxOpenFiles = 100; class LogReader { public: void OpenFile(string local_file); private: int offset_; DISALLOW_COPY_AND_ASSIGN(LogReader); };
原文链接: http://www.cnblogs.com/xinxue/
专注于机器视觉、OpenCV、C++ 编程