1、首先介绍《高质量C++/C 编程指南》,点击下载,下面是我的一些阅读笔记。


2、为了防止头文件被重复引用,应当用ifndef / define / endif 结构产生预处理块。


3、用#include <filename.h> 格式来引用标准库的头文件(编译器将从标准库目录开始搜索)。

4、用#include “filename.h” 格式来引用非标准库的头文件(编译器将从用户的工作目录开始搜索)。


5、头文件的作用:

(1)通过头文件来调用库功能。在很多场合,源代码不便(或不准)向用户公布,只要向用户提供头文件和二进制的库即可。用户只需要按照头文件中的接口声明来调用库功能,而不必关心接口怎么实现的。编译器会从库中提取相应的代码。
(2)头文件能加强类型安全检查。如果某个接口被实现或被使用时,其方式与头文件中的声明不一致,编译器就会指出错误,这一简单的规则能大大减轻程序员调试、改错的负担。


6、一行代码只做一件事情,如只定义一个变量,或只写一条语句。这样的代码容易阅读,并且方便于写注释。


7、尽可能在定义变量的同时初始化该变量(就近原则)如果变量的引用处和其定义处相隔比较远,变量的初始化很容易被忘记。如果引用了未被初始化的变量,可能会导致程序错误。本建议可以减少隐患。


8、代码内的空格规范:

高质量C++/C 编程指南 阅读笔记(一)编程规范_编译器


9、应当将修饰符 * 和& 紧靠变量名
例如:
char *name;
int *x, y; // 此处y 不会被误解为指针


10、简单的 Windows 应用程序命名规则:

类名和函数名用大写字母开头的单词组合而成。

变量和参数用小写字母开头的单词组合而成。

常量全用大写的字母,用下划线分割单词。

静态变量加前缀s_(表示static)。

如果不得已需要全局变量,则使全局变量加前缀g_(表示global)。

类的数据成员加前缀m_(表示member),这样可以避免数据成员与成员函数的参数同名。


11、为了防止某一软件库中的一些标识符和其它软件库中的冲突,可以为各种标识符加上能反映软件性质的前缀。例如三维图形标准OpenGL 的所有库函数均以gl 开头,所有常量(或宏定义)均以GL 开头。


12、运算符的优先级:注意一元运算符+ - * 的优先级高于对应的二元运算符。

高质量C++/C 编程指南 阅读笔记(一)编程规范_初始化_02


13、如果代码行中的运算符比较多,用括号确定表达式的操作顺序,避免使用默认的优先级。


14、不可将布尔变量直接与TRUE、FALSE 或者1、0 进行比较。
根据布尔类型的语义,零值为“假”(记为FALSE),任何非零值都是“真”(记为TRUE)。TRUE 的值究竟是什么并没有统一的标准。例如Visual C++ 将 TRUE 定义为1,而Visual Basic 则将TRUE 定义为-1。假设布尔变量名字为flag,它与零值比较的标准if 语句如下:
if (flag) // 表示flag 为真

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

其它的用法都属于不良风格,例如:
if (flag == TRUE)
if (flag == 1 )
if (flag == FALSE)
if (flag == 0)


15、不可将浮点变量用“==”或“!=”与任何数字比较。
千万要留意,无论是float 还是double 类型的变量,都有精度限制。所以一定要避免将浮点变量用“==”或“!=”与数字比较,应该设法转化成“>=”或“<=”形式。假设浮点变量的名字为x,应当将

if (x == 0.0) // 隐含错误的比较转化为
if ((x>=-EPSINON) && (x<=EPSINON))
其中EPSINON 是允许的误差(即精度)。


16、应当将指针变量用“==”或“!=”与NULL 比较。
指针变量的零值是“空”(记为NULL)。尽管NULL 的值与0 相同,但是两者意义不同。假设指针变量的名字为p,它与零值比较的标准if 语句如下:
if (p == NULL) // p 与NULL 显式比较,强调p 是指针变量
if (p != NULL)

不要写成
if (p == 0) // 容易让人误解p 是整型变量
if (p != 0)
或者
if (p) // 容易让人误解p 是布尔变量
if (!p)


17、不要忘记最后那个default 分支。即使程序真的不需要default 处理,也应该保留语句 default : break; 这样做并非多此一举,而是为了防止别人误以为你忘了default 处理。


18、常量是一种标识符,它的值在运行期间恒定不变。C 语言用 #define 来定义常量(称为宏常量)。C++ 语言除了 #define 外还可以用const 来定义常量(称为const 常量)。


19、为什么需要常量:

如果不使用常量,直接在程序中填写数字或字符串,将会有什么麻烦?
(1) 程序的可读性(可理解性)变差。程序员自己会忘记那些数字或字符串是什么意思,用户则更加不知它们从何处来、表示什么。
(2) 在程序的很多地方输入同样的数字或字符串,难保不发生书写错误。
(3) 如果要修改数字或字符串,则会在很多地方改动,既麻烦又容易出错。


20、C++ 语言可以用const 来定义常量,也可以用 #define 来定义常量。但是前者比后者有更多的优点:
(1) const 常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查。而对后者只进行字符替换,没有类型安全检查,并且在字符替换可能会产生意料不到的错误(边际效应)。
(2) 有些集成化的调试工具可以对const 常量进行调试,但是不能对宏常量进行调试。


21、不要省略返回值的类型:

C 语言中,凡不加类型说明的函数,一律自动按整型处理。这样做不会有什么好处,却容易被误解为void 类型。
C++语言有很严格的类型安全检查,不允许上述情况发生。由于C++程序可以调用C 函数,为了避免混乱,规定任何C++/ C 函数都必须有类型。如果函数没有返回值,那么应声明为void 类型。


22、不要将正常值和错误标志混在一起返回。正常值用输出参数获得,而错误标志用return 语句返回。


23、有时候函数原本不需要返回值,但为了增加灵活性如支持链式表达,可以附加返回值。


24、程序一般分为 Debug 版本和Release 版本,Debug 版本用于内部调试,Release 版本发行给用户使用。断言 assert 是仅在Debug 版本起作用的宏,它用于检查“不应该”发生的情况。


25、引用与指针:

引用是 C++中的概念,初学者容易把引用和指针混淆一起。一下程序中,n 是m 的一个引用(reference),m 是被引用物(referent)。
int m;
int &n = m;
n 相当于m 的别名(绰号),对n 的任何操作就是对m 的操作。例如有人名叫王小毛,他的绰号是“三毛”。说“三毛”怎么怎么的,其实就是对王小毛说三道四。所以n 既不是m 的拷贝,也不是指向m 的指针,其实n 就是m 它自己。
引用的一些规则如下:
(1)引用被创建的同时必须被初始化(指针则可以在任何时候被初始化)。
(2)不能有NULL 引用,引用必须与合法的存储单元关联(指针则可以是NULL)。
(3)一旦引用被初始化,就不能改变引用的关系(指针则可以随时改变所指的对象)。


26、内存分配方式有三种:
(1) 从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量,static 变量。
(2) 在上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集
中,效率很高,但是分配的内存容量有限。
(3) 从上分配,亦称动态内存分配。程序在运行的时候用malloc 或new 申请任意多少的内存,程序员自己负责在何时用free 或delete 释放内存。动态内存的生存期由我们决定,使用非常灵活,但问题也最多。


27、待续