2011年3月31日

初步接触Google Style和Cpplint

试着看了一下Google Style的C++编码规范,先随手写了一个最简单的程序来试试Cpplit。代码如下
------------------------------------
#include <iostream>

using namespace std;

int main() {
    cout << "Hello World!" << endl;
    return 0;
}
------------------------------------
运行指令
------------------------------------
g++ main.cpp -o main
./main
------------------------------------
得到结果
------------------------------------
Hello World!

------------------------------------
运行Cpplint,得到的结果如下
------------------------------------
main.cpp:0:  No copyright message found.  You should have a line: "Copyright [year] <Copyright Owner>"  [legal/copyright] [5]
main.cpp:1:  Streams are highly discouraged.  [readability/streams] [3]
main.cpp:3:  Do not use namespace using-directives.  Use using-declarations instead.  [build/namespaces] [5]
Done processing main.cpp
Total errors found: 3
------------------------------------
第一条说我没有版权信息,第二条没看懂,第三条说的是不能用std全部空间,建议使用具体用到的函数。

仔细上网查了半天,终于弄懂了第二条是什么意思。

------------------------------------------
5.9. 流
Tip 只在记录日志时使用流.
定义: 流用来替代 printf() 和 scanf().
优点: 有了流, 在打印时不需要关心对象的类型. 不用担心格式化字符串与参数列表不匹配 (虽然在 gcc 中使用 printf 也不存在这个问题). 流的构造和析构函数会自动打开和关闭对应的文件.
缺点: 流使得 pread() 等功能函数很难执行. 如果不使用 printf 风格的格式化字符串, 某些格式化操作 (尤其是常用的格式字符串 %.*s) 用流处理性能是很低的. 流不支持字符串操作符重新排序 (%1s), 而这一点对于软件国际化很有用.
结论: 不要使用流, 除非是日志接口需要. 使用 printf 之类的代替.

使用流还有很多利弊, 但代码一致性胜过一切. 不要在代码中使用流.

拓展讨论:
对这一条规则存在一些争论, 这儿给出点深层次原因. 回想一下唯一性原则 (Only One Way): 我们希望在任何时候都只使用一种确定的 I/O 类型, 使代码在所有 I/O 处都保持一致. 因此, 我们不希望用户来决定是使用流还是 printf + read/write. 相反, 我们应该决定到底用哪一种方式. 把日志作为特例是因为日志是一个非常独特的应用, 还有一些是历史原因.

流的支持者们主张流是不二之选, 但观点并不是那么清晰有力. 他们指出的流的每个优势也都是其劣势. 流最大的优势是在输出时不需要关心打印对象的类型. 这是一个亮点. 同时, 也是一个不足: 你很容易用错类型, 而编译器不会报警. 使用流时容易造成的这类错误:
cout << this;   // Prints the address
cout << *this;  // Prints the contents
由于 << 被重载, 编译器不会报错. 就因为这一点我们反对使用操作符重载.

有人说 printf 的格式化丑陋不堪, 易读性差, 但流也好不到哪儿去. 看看下面两段代码吧, 实现相同的功能, 哪个更清晰?
cerr << "Error connecting to '" << foo->bar()->hostname.first
     << ":" << foo->bar()->hostname.second << ": " << strerror(errno);

fprintf(stderr, "Error connecting to '%s:%u: %s",
        foo->bar()->hostname.first, foo->bar()->hostname.second,
        strerror(errno));
你可能会说, “把流封装一下就会比较好了”, 这儿可以, 其他地方呢? 而且不要忘了, 我们的目标是使语言更紧凑, 而不是添加一些别人需要学习的新装备.

每一种方式都是各有利弊, “没有最好, 只有更适合”. 简单性原则告诫我们必须从中选择其一, 最后大多数决定采用 printf + read/write.
------------------------------------------

最终改好的程序如下,Cpplint能通过,g++也能通过
------------------------------------------
// Copyright 2011 Bill_Lang
#include <cstdio>
int main() {
    printf("Hello World!");
    return 0;
}
------------------------------------------

直接看Google Style会一会儿就烦了,但是配合着使用Cpplint,还是挺有乐趣的。看来还能帮助自己提高C++编程的实际水平。

推荐朋友们也玩玩这个。

没有评论: