1、文件结构

  C/C++程序通常分为两个文件,一个文件用于保存程序的声明,一个文件用于保存程序的实现。

1.1 版权和版本的声明
版权和版本的声明位于头文件和定义文件的开头,主要内容有:
(1)版权信息
(2)文件名称,标识符,摘要
(3)当前版本号,作者/修改者,完成日期
(4)版本历史信息

1.2 头文件的结构
头文件由三部分内容组成:
1)头文件开头处的版权和版本声明。
2)预处理块。

3)函数和类结构声明等。

1.3 定义文件的结构
定义文件有三部分内容:
1) 定义文件开头处的版权和版本声明。
2) 对一些头文件的引用。
3) 程序的实现体(包括数据和代码)。

1.4 目录结构
如果一个软件的头文件数目比较多(如超过十个),通常应将头文件和定义文件分别保存于不同的
目录,以便于维护。

命名规则
共性规则

1、标识符的长度应当符合“min-length && max-information”原则

2、程序中不要出现仅靠大小写区分的相似的标识符。

3、程序中不要出现标识符完全相同的局部变量和全局变量,尽管两者的作用域不同而不会
发生语法错误,但会使人误解

4、变量的名字应当使用“名词”或者“形容词+名词”。

5、全局函数的名字应当使用“动词”或者“动词+名词”(动宾词组)。类的成员函数应
当只使用“动词”,被省略掉的名词就是对象本身

6、用正确的反义词组命名具有互斥意义的变量或相反动作的函数等。

Windows 应用程序命名规则

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

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

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

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

5、如果需要定义全局变量,则使全局变量加前缀g_(表示global)。

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

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

 Linux 应用程序函数命名规则

函数命名应遵循下面两个原则:
1)属于某一模块的函数,加上前缀,前缀为模块缩写;

2)函数名应该表明函数意义,格式为"前缀_名词_动词";

复合表达式

1、不要编写太复杂的复合表达式。

2、不要有多用途的复合表达式。

3、不要把程序中的复合表达式与“真正的数学表达式”混淆。

if (a < b < c) // a < b < c 是数学表达式而不是程序表达式
并不表示 if ((a<b) && (b<c))

if 语句

1 布尔变量与零值比较

不可将布尔变量直接与TRUE、FALSE 或者1、0 进行比较。

假设布尔变量名字为flag,它与零值比较的标准if 语句如下:
if (flag) // 表示flag 为真
if (!flag) // 表示flag 为假
其它的用法都属于不良风格,例如:
if (flag == TRUE)
if (flag == 1 )
if (flag == FALSE)
if (flag == 0)

2 整型变量与零值比较
应当将整型变量用“==”或“!=”直接与0 比较。

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

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

4 指针变量与零值比较
【规则4-3-4】应当将指针变量用“==”或“!=”与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)

循环语句的效率

1、在多重循环中,如果有可能,应当将最长的循环放在最内层,最短的循环放在最外层,

以减少CPU 跨切循环层的次数。

2、如果循环体内存在逻辑判断,并且循环次数很大,宜将逻辑判断移到循环体的外面。

for 语句的循环控制变量

1、不可在for 循环体内修改循环变量,防止for 循环失去控制。

2、建议for 语句的循环控制变量的取值采用“半开半闭区间”写法。

switch 语句

1】每个case 语句的结尾不要忘了加break,

2】不要忘记最后那个default 分支。

常量

1 const 与#define 的比较

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

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

  1】尽量使用含义直观的常量来表示那些将在程序中多次出现的数字或字符串。

  2】在C++ 程序中只使用const 常量而不使用宏常量,即const 常量完全取代宏常量

2 常量定义规则

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

2】如果某一常量与其它常量密切相关,应在定义中包含这种关系,而不应给出一些孤立的
值。

函数设计
一个函数的注释信息如下例:
/**********************************************************************************
* Function: calculate The area of rectangle *
* parameter: the Length and Width of

rectangle *
* outout: the area of rectangle *
***********************************************************************************/
int GetValue(int iLength,int iWidth)
{
… … ..
return iArea;
}

1 参数的规则
  1】参数的书写要完整,不要贪图省事只写参数的类型而省略参数名字。如果函数没有参数,
则用void 填充。

  2】参数命名要恰当,顺序要合理。

  3】如果参数是指针,且仅作输入用,则应在类型前加const,以防止该指针在函数体内被意
外修改

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

  5】参数缺省值只能出现在函数的声明中,而不能出现在定义体中。

  6】如果函数有多个参数,参数只能从后向前挨个儿缺省,否则将导致函数调用语句怪模怪

  7】避免函数有太多的参数,参数个数尽量控制在5 个以内。如果参数太多,在使用时容易
将参数类型或顺序搞错。

  8】尽量不要使用类型和数目不确定的参数。

2 返回值的规则

  1】不要省略返回值的类型。

  2】函数名字与返回值类型在语义上不可冲突

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

  4】给以“指针传递”方式的函数返回值加 const 修饰,那么函数返回值(即指针)的内容
不能被修改,该返回值只能被赋给加 const 修饰的同类型指针。

  5】函数返回值采用“值传递方式”,由于函数会把返回值复制到外部临时的存储单元中,
加 const 修饰没有任何价值。

  6】函数返回值采用“引用传递”的场合并不多,这种方式一般只出现在类的赋值函数中,
目的是为了实现链式表达。

3 函数内部实现的规则

  1】在函数体的“入口处”,对参数的有效性进行检查。
  2】在函数体的“出口处”,对return 语句的正确性和效率进行检查。

 

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

(2)要搞清楚返回的究竟是“值”、“指针”还是“引用”。
(3)如果函数返回值是一个对象,要考虑return 语句的效率。

其它建议

  1】函数的功能要单一,不要设计多用途的函数。
  2】函数体的规模要小,尽量控制在50 行代码之内。

  3】尽量避免函数带有“记忆”功能。相同的输入应当产生相同的输出。带有“记忆”功能
的函数,其行为可能是不可预测的,因为它的行为可能取决于某种“记忆状态”。这样的函数既不易理
解又不利于测试和维护。在C/C++语言中,函数的static 局部变量是函数的“记忆”存储器。建议尽量
少用static 局部变量,除非必需

  4】不仅要检查输入参数的有效性,还要检查通过其它途径进入函数体内的变量的有效性,
例如全局变量、文件句柄等。
  5】用于出错处理的返回值一定要清楚,让使用者不容易忽视或误解错误情况

引用与指针的比较
引用是C++中的概念,容易把引用和指针混淆。
引用的一些规则如下:
(1)引用被创建的同时必须被初始化(指针则可以在任何时候被初始化)。
(2)不能有NULL 引用,引用必须与合法的存储单元关联(指针则可以是NULL)。
(3)一旦引用被初始化,就不能改变引用的关系(指针则可以随时改变所指的对象)

普通函数重载

  1】重载函数中的参数不同(包括类型、顺序不同),才是重载函数,而仅仅返回值不同
则不行。
  2】当心隐式类型转换导致重载函数产生二义性,数字本身没有类型,将数字当作参数时
将自动进行类型转换(称为隐式类型转换)。
成员函数的重载、覆盖与隐藏

  1】成员函数的重载、覆盖(override)与隐藏很容易混淆,注意区分。
  2】注意如果派生类的函数与基类的函数同名,但是参数不同。此时,不论有无 virtual
关键字,基类的函数将被隐藏(注意别与重载混淆)。
  3】注意如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有
virtual 关键字。此时,基类的函数被隐藏(注意别与覆盖混淆)

内联函数

  1】尽量用内联取代宏代码,提高函数的执行效率(速度)。
  2】关键字 inline 必须与函数定义体放在一起才能使函数成为内联,仅将 inline 放在函
数声明前面不起任何作用。
  3】如果函数体内的代码比较长或函数体内出现循环,则不宜使用内联

内存管理

内存分配方式有三种:
(1) 从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都
存在。例如全局变量,static 变量

(2) 在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这
些存储单元自动被释放。栈栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有

限。

(3) 从堆上分配,亦称动态内存分配。程序在运行的时候用malloc 或new 申请任意多少的内存,程
序员自己负责在何时用free 或delete 释放内存。动态内存的生存期由我们决定,使用非常灵活,但问

题也最多

  1】用malloc 或new 申请内存之后,应该立即检查指针值是否为NULL。防止使用指针值为NULL
的内存。

  2】不要忘记为数组和动态内存赋初值。防止将未被初始化的内存作为右值使用。
  3】避免数组或指针的下标越界,特别要当心发生“多1”或者“少1”操作。

  4】动态内存的申请与释放必须配对,防止内存泄漏。
  5】用free 或delete 释放了内存之后,立即将指针设置为NULL,防止产生“野指针”。

类的构造函数

  1】“缺省的拷贝构造函数”和“缺省的赋值函数”均采用“位拷贝”而非“值拷贝”的方式来实现,若类中含有指针变量,不能采用缺省的方式

  2】如果类存在继承关系,派生类必须在其初始化表里调用基类的构造函数。

  3】类的 const 常量只能在初始化表里被初始化,因为它不能在函数体内用赋值的方式来初始化。

  4】非内部数据类型的成员对象采用初始化表的方式初始化较好。
  5】拷贝构造函数和赋值函数非常容易混淆,常导致错写、错用。拷贝构造函数是在对象被创建时调用的,而赋值函数只能被已经存在了的对象调用

成员函数

1】任何不会修改数据成员的函数都应该声明为 const 类型

类的继承和组合

  1】如果类 A 和类 B 毫不相关,不可以为了使 B 的功能更多些而让 B 继承 A 的功能和属性

  2】若在逻辑上 B 是 A 的“一种情况”,则允许 B 继承 A 的功能和属性。

  3】若在逻辑上 A 是 B 的“一部分”(a part of),则不允许 B 从 A 派生,而是要用 A 和其它东西组合出 B

提高程序的效率

  1】不要一味地追求程序的效率,应当在满足正确性、可靠性、健壮性、可读性等质量因素的前提下,设法提高程序的效率。

  2】以提高程序的全局效率为主,提高局部效率为辅。

  3】在优化程序的效率时,应当先找出限制效率的“瓶颈”,不要在无关紧要之处优化。
  4】先优化数据结构和算法,再优化执行代码。

  5】有时候时间效率和空间效率可能对立,此时应当分析那个更重要,作出适当的折衷。例如多花费一些内存来提高性能

  6】不要追求紧凑的代码,因为紧凑的代码并不能产生高效的机器码。

最新文章

  1. 模拟提交API数据Pyqt版
  2. [PHP] - Apache + PHP 环境搭建
  3. 运算符&amp;,|,^
  4. adb操作命令详解及大全
  5. iOS开发——UI篇Swift篇&amp;UIDatePicker
  6. Linux学习——粘粘今天看的东西
  7. ubuntu apache2 流量限制模块
  8. 利用工具MailUtils实现邮件的发送,遇到的大坑,高能预警!!
  9. Day1作业要求
  10. golang 常见疑惑总结
  11. NodeJs加载站点的所有页面不存在则404
  12. jquery 选择对象随心所欲,遍历数组更是易如反掌
  13. Max Chunks To Make Sorted LT769
  14. Gitlab Webhooks, External Services, and API(二)
  15. ID3D11DeviceContext::DrawIndexed DrawIndexed 参数详解 StartIndexLocation BaseVertexLocation
  16. 【驱动】网卡驱动&#183;linux内核网络分层结构
  17. day5模块学习--yaml文件处理
  18. The filename 未命名.ipa in the package contains an invalid character(s). The valid characters are: A-Z, a-z, 0-9, dash, period, underscore, but the name cannot start with a dash, period, or underscore
  19. ThinkPHP -- 去除URL中的index.php
  20. [Functional Programming] Write a simple version of Maybe

热门文章

  1. Leetcode数组题*3
  2. 关于EasyUI DataGrid行编辑时嵌入时间控件
  3. 831. KMP字符串(模板)
  4. opencv 实现人脸检测(harr特征)
  5. 更新centos本地仓库(换源)
  6. Highcharts中文帮助文档
  7. [CF1220C] Substring Game in the Lesson - 博弈论
  8. spring boot使用freemarker模版整合spring Data JPA
  9. codeforces 1288C. Two Arrays(dp)
  10. Ninject 2.x细说---1.基本使用