zoukankan      html  css  js  c++  java
  • Google Style的C++编码规范

    试着看了一下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++编程的实际水平。

    推荐朋友们也玩玩这个。

    from:http://billlangjun.wordpress.com/2011/03/31/

    ========================================================================

    写代码时必须注重代码规范。养成良好的程序风格有助于提高代码的可维护性与可阅读性。
    Google推出了自己的《Google C++ 风格指南》,在这份指南中各种C++编程中遇到的风格问题都得到了规范。由于原版篇幅过长,我在这里整理一份简化版的编程规范,以供各位参考。同时希望每一位狂想曲创作组成员都能够用此代码规范编程。
    注意:此份资料仅仅是Google推荐的代码风格,不代表所有程序都要用此套规范编写,当然我们还是强烈建议在建立任何项目或是工程之前,都应该统一风格,以便日后维护。
    此套代码规范与常用的一些规范(如匈牙利命名法等)可能有所出入,如果您是第一次使用,也许会感到些许不适应,但还请多多习惯此种编码规范。
    另:本文档仅仅介绍的是C++编码风格指南,而并非编程规范或是编程优化指南,如若想了解更多的代码优化方法(如使用何种输入输出方式等)还请参考《effective C++》与《more effective C++》等著作。
    好了,下面开始我们正式的风格规范探索。

    一、头文件
    1. 头文件写在.h文件中,实现文件写在.cc中而不是写在.cpp中。
    2. 每个.cc文件都对应一个.h文件,包含main()函数的文件除外。
    3. 每个头文件都要用#define保护,格式:

    #ifndef FOO_BAR_BAZ_H_
    #define FOO_BAR_BAZ_H_
    …
    #endif // FOO_BAR_BAZ_H_

    4. 只有当函数少于10行时才建议使用内联函数,内联中包含循环或switch语句反而会降低效率。(Frankie注:不建议在内联函数中再调用其他函数)
    5. 复杂的内联函数与函数模板建议放在-inl.h文件中,并用#define保护。
    6. 函数参数顺序:先输入参数,然后输出参数。
    7. #include路径及顺序:该.cc的.h头文件、C库、C++库、其他库的.h文件、本项目内的.h文件。

    二、作用域
    1. 鼓励在.cc文件内使用匿名名字空间。不要在.h文件中使用匿名空间。
    2. 使用具名的名字空间时用名字把.h文件及.cc文件中除前置声明外的源文件全部封装起来。

    // .h 文件
    namespace mynamespace {
    // 所有声明都置于命名空间中
    // 注意不要使用缩进
    class MyClass {
     public:
     …
     void Foo();
    };
    } // namespace mynamespace
    // .cc 文件
    namespace mynamespace {
    // 函数定义都置于命名空间中
    void MyClass::Foo() {
     …
    }
    } // namespace mynamespace

    3. 最好不使用using namespace,而使用using ::foo::bar;类型。
    4. 尽量不使用裸的全局函数,而要使用静态成员函数或名字空间内的非成员函数。
    5. 尽可能将变量至于最小作用域内,尽可能用初始化方式替代声明再赋值,遇到for循环则要考虑效率问题(@July,代码大全,深入理解计算机系统都有阐述)。如:

    // 低效的实现
    for (int i = 0; i < 1000000; ++i) {
    Foo f; // 构造函数和析构函数分别调用 1000000 次!
    f.DoSomething(i);
    }


    // 高效的实现
    Foo f; // 构造函数和析构函数只调用 1 次
    for (int i = 0; i < 1000000; ++i) {
     f.DoSomething(i);
    }

    6. 禁止使用class类型的静态或全局变量,包括STL容器,尤其是在多线程中。

    三、
    1. 构造函数只初始化那些没什么意义的(trivial)数据,有意义的(non-trivial)数据建议使用Init()函数。
    2. 如果类定义了若干成员变量且无其他构造函数,则需要定义一个默认构造函数。
    3. 仅当只有数据时使用struct,其他一概使用class。

    四、其他C++特性
    1. 输入参数是值参或const引用,输出参数为指针。输入参数可以为const指针,但决不能为非const的引用参数。
    2. 仅在输入参数类型不同但功能相同时使用重载函数,不要用函数重载去模拟缺省函数参数。
    3. 不允许使用缺省函数参数。
    4. 不使用异常。(Frankie注:我的理解是这是因为Google自身代码的健壮性造成的。Google认为使用异常并不能提高效率)
    5. 禁止使用RTTI。
    6. 使用C++类型转换,如static_cast<>()而不是不要使用 int y = (int)x或 int y = int(x) 等转换方式。
    7. 不要使用流而要使用printf()与scanf()(@July,尽量,但不盲从)。记录日志除外。
    8. 尽量使用前置自增自减,尤其是对迭代器和模板类型。
    9. 尽可能使用const。
    10. 使用断言来指出变量为非负数,而不是使用无符号整型。
    11. 整数用 0, 实数用 0.0, 指针用 NULL, 字符 (串) 用 '\0'。
    12. 尽可能用 sizeof(varname) 代替 sizeof(type)。
    13. 只是用Boost中被认可的库。

    五、命名规定
    1. 尽可能给出描述性的名称,如:int num_errors; int num_completed_connections;
    2. 函数名通常是指令性的,如OpenFile(), set_num_errors()。
    3. 文件名要全部小写,可以包含下划线或连字符。(Frankie注:《狂想曲》统一使用下划线)
    4. 类型名称的每个单词首字母均大写且不含下划线:MyExcitingClass, MyExcitingEnum。
    5. 变量命名一律小写,单词之间以下划线连接。类成员变量以下划线结尾。如:
    my_exciting_local_variable
    my_exciting_member_variable_
    6. 结构体变量的数据成员命名与普通变量一样。
    7. 常量命名在名称前加k:kDaysInAWeek。
    8. 常规函数每个单词首字母大写,没有下划线。
    9. get和set函数要与存取的变量名匹配。如:

    class MyClass {
     public:
     ...
     int num_entries() const { return num_entries_; }
     void set_num_entries(int num_entries) { num_entries_ = num_entries; }
     
     private:
     int num_entries_;
    };

    10. 名字空间用小写字母命名,用下划线连接单词。
    11. 枚举的命名与常量或宏一致:kEnumName或ENUM_NAME,并且建议使用前者,即常量风格的命名方式。
    12. 宏命名全部大写,单词之间用下划线连接。(Frankie注:#define保护文件要用下划线结尾)

    六、注释(Frankie注:此处为本人根据实际结合Google代码规范提出的注释方法,适用于《狂想曲》)
    1. 使用
    2. 在每个文件头加入版权公告,注明作者、修改日期、版本号等信息(只要是我们内部人员,就只标明作者)。
    3. 函数或者变量等的注释没有太多要求,只需注意对齐,内容详尽即可。
    4. 对尚未完成或者需要改进的代码使用TODO注释。如:

    // TODO(kl@gmail.com) Use a "*" here for concatenation operator.
    // TODO(Zeke) change this to use relations.

    TODO需要大写,括号内是您的名字,后接修改的方案等,是为了在“将来某一天做某事”,可以加上明确的时间或明确的事项。

    七、格式(Frankie注:格式内容涉及面较广,详细请参见Google代码风格指南源文档)
    1. 每行代码字符数不超过80。
    2. 用UTF-8编码。
    3. 只是用空格不适用制表位,每次缩进2个空格。
    4. 返回类型和函数名在同一行,参数尽量放在同一行。
    5. if, else, switch等语句一定要使用大括号{}。

    from:http://tctop.wikispaces.com/Google%E4%BB%A3%E7%A0%81%E9%A3%8E%E6%A0%BC%E6%8C%87%E5%8D%97%E6%95%B4%E7%90%86

  • 相关阅读:
    bzoj 1208: [HNOI2004]宠物收养所
    bzoj 1207: [HNOI2004]打鼹鼠
    【NOIP模拟赛】小奇的矩阵
    【NOIP模拟赛】小奇挖矿 2
    Making the Grade POJ
    POJ 3616Milking Time
    [USACO08JAN]电话线Telephone Lines
    Radar Installation POJ
    Warfare And Logistics UVA
    【NOIP2009】最优贸易
  • 原文地址:https://www.cnblogs.com/dkblog/p/2184752.html
Copyright © 2011-2022 走看看