• 林锐C/C++高质量编程指南笔记之一


    C/C++高质量编程指南之一

    第一章:文件结构

    1 在文件开头加上版本信息。

    【规则 1-2-1】为了防止头文件被重复引用,应当用 ifndef/define/endif 结构产生预处理块

    【规则 1-2-2】用 #include <filename.h> 格式来引用标准库的头文件(编译器将从 标准库目录开始搜索) 

    【规则 1-2-3】用 #include “filename.h” 格式来引用非标准库的头文件(编译器将 从用户的工作目录开始搜索) 

    【建议 1-2-1】头文件中只存放“声明”而不存放“定义” 

    第二章:程序的版式

    【规则 2-1-1】在每个类声明之后、每个函数定义结束之后都要加空行。

    【规则 2-1-2】在一个函数体内,逻揖上密切相关的语句之间不加空行,其它地方应 加空行分隔。

    【规则 2-2-1】一行代码只做一件事情,如只定义一个变量,或只写一条语句。

    【规则 2-2-2】if、for、while、do 等语句自占一行,执行语句不得紧跟其后。不论 执行语句有多少都要加{}。这样可以防止书写失误

    【建议 2-2-1】尽可能在定义变量的同时初始化该变量(就近原则) 

    【规则 2-3-1】关键字之后要留空格。

    【规则 2-3-2】函数名之后不要留空格,紧跟左括号‘(’,以与关键字区别

    【规则 2-3-5】 “=”、“+=” “>=”、“<=”、“+”、“*”、“%”、“&&”、“||”、“<<”,“^”等二元 操作符的前后应当加空格

    【规则 2-3-6】一元操作符如“!”、“~”、“++”、“--”、“&”(地址运算符)等前后不 加空格。 

    【建议 2-3-1】对于表达式比较长的 for 语句和 if 语句,为了紧凑起见可以适当地去 掉一些空格,

            如 for (i=0; i<10; i++)和 if ((a<=b) && (c<=d)) 

     【规则 2-4-1】程序的分界符‘{’和‘}’应独占一行并且位于同一列,同时与引用 它们的语句左对齐。

     【规则 2-4-2】{ }之内的代码块在‘{’右边数格处左对齐。 

    注意:这个是有争议的,可能只是在C/C++中这样去做,在其他语言中好像不是这样的,

    我的习惯是第一个。

    长行拆分:

     【规则 2-6-1】应当将修饰符 * 和 & 紧靠变量名

    char  *name;  int   *x, y; // 此处 y 不会被误解为指针 

    【规则 2-7-6】注释的位置应与被描述的代码相邻,可以放在代码的上方或右方,不 可放在下方。 

     第三章:命名规则

    这块好好看看哈。

    【规则 3-1-3】命名规则尽量与所采用的操作系统或开发工具的风格保持一致。

    例如 Windows 应用程序的标识符通常采用“大小写”混排的方式,如 AddChild。

    而 Unix 应用程序的标识符通常采用“小写加下划线”的方式,如 add_child。

    【规则 3-1-6】变量的名字应当使用“名词”或者“形容词+名词” 。 

    float  value; 
    float  oldValue; 
    float  newValue; 

    【规则 3-1-7】全局函数的名字应当使用“动词”或者“动词+名词”(动宾词组) 。

      类的成员函数应当只使用“动词”,被省略掉的名词就是对象本身。 

    DrawBox();  // 全局函数  
    box->Draw();  // 类的成员函数 

    【建议 3-1-1】尽量避免名字中出现数字编号,如 Value1,Value2 等,除非逻辑上的 确需要编号

    【规则 3-2-1】类名和函数名用大写字母开头的单词组合而成。 例如: 

     class Node;     // 类名  
    class LeafNode;    // 类名  
    void  Draw(void);   // 函数名  
    void  SetValue(int value); // 函数名 

    【规则 3-2-2】变量和参数用小写字母开头的单词组合而成。 

    BOOL flag; 
    int  drawMode; 
    
    也可以这样:
    string window_name;  // OK 使用下划线
    string windowname;   // OK 全部小写
    string windowName;   // Bad 大小写混合使用
    全局变量:没有特殊要求,尽量少用?可以加上前缀g_以与局部变量区分。
    
    类的成员变量:可以加上前缀m_
    当然也有就加一个_的

    【规则 3-2-3】常量全用大写的字母,用下划线分割单词

    const int MAX = 100;  
    const int MAX_LENGTH = 100;

    【规则 3-2-4】静态变量加前缀 s_(表示 static)

      static int s_initValue; // 静态变量 

    【规则 3-2-5】如果不得已需要全局变量,则使全局变量加前缀 g_(表示 global)。 

      int g_howMuchMoney; // 全局变量 

    【规则 3-2-6】类的数据成员加前缀 m_(表示 member),这样可以避免数据成员与 成员函数的参数同名。

     第四章:表达式和基本语句

    【规则 4-1-1】如果代码行中的运算符比较多,用括号确定表达式的操作顺序,避免 使用默认的优先级。 

    与零值比较:

    布尔变量与零值比较 

    【规则 4-3-1】不可将布尔变量直接与 TRUE、FALSE 或者 1、0 进行比较。 

        假设布尔变量名字为 flag,它与零值比较的标准 if 语句如下:

         if (flag) // 表示 flag 为真 

        if (!flag) // 表示 flag 为假 

     整型变量与零值比较 :

    【规则 4-3-2】应当将整型变量用“==”或“!=”直接与 0 比较。

      if (value == 0)   

      if (value != 0)

     浮点变量与零值比较 :

     【规则 4-3-3】不可将浮点变量用“==”或“!=”与任何数字比较。 

    千万要留意,无论是 float 还是 double 类型的变量,都有精度限制。

    所以一定要避 免将浮点变量用“==”或“!=”与数字比较,应该设法转化成“>=”或“<=”形式。 

    正确的比较方式

      if ((x>=-EPSINON) && (x<=EPSINON)) 其中 EPSINON 是允许的误差(即精度) 。

      其中EPSINON是允许的误差(即精度)。 const float EPSINON = 0.000001,至于为什么取0.000001,可以自己按实际情况定义。

    指针变量与零值比较 

    【规则 4-3-4】应当将指针变量用“==”或“!=”与 NULL 比较

       if (p == NULL) // p 与 NULL 显式比较,强调 p 是指针变量   

      if (p != NULL)

    【建议 4-4-1】在多重循环中,如果有可能,应当将长的循环放在内层,短的 循环放在外层,以减少 CPU 跨切循环层的次数

    第五章:常量


    为什么需要常量:

    如果不使用常量,直接在程序中填写数字或字符串,将会有什么麻烦?

    (1) 程序的可读性(可理解性)变差。程序员自己会忘记那些数字或字符串是什么意 思,用户则更加不知它们从何处来、表示什么。

    (2) 在程序的很多地方输入同样的数字或字符串,难保不发生书写错误。

    (3) 如果要修改数字或字符串,则会在很多地方改动,既麻烦又容易出错。 

    【规则 5-1-1】 尽量使用含义直观的常量来表示那些将在程序中多次出现的数字或 

    #define      MAX   100  /*  C 语言的宏常量  */  
    const int    MAX = 100;  //  C++ 语言的 const 常量 
    const float  PI = 3.14159; //  C++ 语言的 const 常量

    const和define的比较

    C++ 语言可以用 const 来定义常量,也可以用 #define 来定义常量。但是前者比后 者有更多的优点:

    (1) const 常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安 全检查。而对后者只进行字符替换,没有类型安全检查,并且在字符替换可能会 产生意料不到的错误(边际效应)。

    (2) 有些集成化的调试工具可以对 const常量进行调试,但是不能对宏常量进行调试。


    【规则 5-2-1】在 C++ 程序中只使用 const 常量而不使用宏常量,即 const 常量完 全取代宏常量。

    【规则 5-3-1】需要对外公开的常量放在头文件中,不需要对外公开的常量放在定义 文件的头部。为便于管理,可以把不同模块的常量集中存放在一个公共的头文件中。

    第六章:函数设计

    【规则 6-1-2】参数命名要恰当,顺序要合理。 

      应将目的参数放在前面,源参数放在后面。

    例如编写字符串拷贝函数 StringCopy

    void StringCopy(char *strDestination,const char *strSource);

    调用时:StringCopy(str, “Hello World”);

    【规则 6-1-4】如果输入参数以值传递的方式传递对象,则宜改用“const &”方式来 传递,这样可以省去临时对象的构造和析构过程,从而提高效率   

    【建议 6-2-1】有时候函数原本不需要返回值,但为了增加灵活性如支持链式表达, 

      例如字符串拷贝函数 strcpy 的原型: 

      char *strcpy(char *strDest,const char *strSrc);

      适用于:int  length = strlen( strcpy(str, “Hello World”) );

    【规则 6-3-1】在函数体的“入口处”,对参数的有效性进行检查 用assert

     【规则 6-3-2】在函数体的“出口处”,对 return 语句的正确性和效率进行检查。 

     (1)return 语句不可返回指向“栈内存”的“指针”或者“引用”,因为该内存在函数 体结束时被自动销毁。

      例如 

    char * Func(void) 
     {   
            char str[] = “hello world”; // str 的内存位于栈上   …  
            return str;  // 将导致错误  
     }   

    (2)要搞清楚返回的究竟是“值” 、“指针”还是“引用” 

    (3)如果函数返回值是一个对象,要考虑 return 语句的效率。

      例如       return String(s1 + s2); 

    这是临时对象的语法,表示“创建一个临时对象并返回它”。

    不要以为它与“先创建 一个局部对象 temp 并返回它的结果”是等价的,

    如:

      String temp(s1 + s2);

      return temp;  。

    实质不然,上述代码将发生三件事。

    首先,temp 对象被创建,同时完成初始化;

    然 后拷贝构造函数把 temp 拷贝到保存返回值的外部存储单元中;

    最后,temp 在函数结束 时被销毁(调用析构函数)。

    然而“创建一个临时对象并返回它”的过程是不同的,编译 器直接把临时对象创建并初始化在外部存储单元中,省去了拷贝和析构的化费,提高了 效率。

    第七章到最后

    https://www.cnblogs.com/xiaokang01/p/12716736.html

  • 相关阅读:
    iPhone UIButton图标与文字间距设置【转】
    UIButton左边图片右边文字的做法
    UICollectionViewCell设置阴影
    ARC中__bridge, __bridge__transfer, __bridge_retained 关系
    NSFileHandle的用法(用于读写文件)
    自定义FrameWork
    IOS7 适配以及向下兼容问题
    IOS 7 UITableView cell lines不能靠左解决方法
    xml报错“cvc-complex-type.2.4.c: The matching wildcard is strict, but no declaration can be found for element”
    《Effective Java》笔记 :(一)创建和销毁对象
  • 原文地址:https://www.cnblogs.com/xiaokang01/p/12710405.html
Copyright © 2020-2023  润新知