林锐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

posted @ 2020-04-16 16:07  Lucky&  阅读(1383)  评论(0编辑  收藏  举报
//返回顶部开始
//返回顶部结束