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

摘要:
首先,我们强烈推荐林锐博士的《高质量C++/C编程指南》。请花一两个小时仔细阅读这本100页的经典,你会受益匪浅。对于//在良好的样式中,长行分割代码的最大长度应控制在70到80个字符内。提高循环体效率的基本途径是降低循环体的复杂性。

首先,强烈推荐林锐博士这本《高质量C++/C 编程指南》,请花一两个小时认真阅读这本百页经书,你将会获益匪浅。草草看过,个人收获记录如下。
头文件的作用略作解释:
(1)通过头文件来调用库功能。在很多场合,源代码不便(或不准)向用户公布,只要向用户提供头文件和二进制的库即可。用户只需要按照头文件中的接口声明来调用库功能,而不必关心接口怎么实现的。编译器会从库中提取相应的代码。
(2)头文件能加强类型安全检查。如果某个接口被实现或被使用时,其方式与头文件中的声明不一致,编译器就会指出错误,这一简单的规则能大大减轻程序员调试、改错的负担。
另:extern可以置于变量或者函数前,以标示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义。如果函数的声明中带有关键字extern,仅仅是暗示这个函数可能在别的源文件里定义,没有其它作用。
空行
a.在每个类声明之后、每个函数定义结束之后都要加空行。
b.在一个函数体内,逻揖上密切相关的语句之间不加空行,其它地方应加空行分隔。(这一条值得注意)
代码行
a.一行代码只做一件事情,如只定义一个变量,或只写一条语句。这样的代码容易阅读,并且方便于写注释。
b.if、for、while、do 等语句自占一行,执行语句不得紧跟其后。不论执行语句有多少都要加{}。这样可以防止书写失误。

for(initalization;contition;update)

{
    dosomething();
}
//空行
other();

c.尽可能在定义变量的同时初始化该变量(就近原则)
代码行内的空格
a.关键字后要留空格,如const、virtual、inline、case以及if、for、while;函数名之后不要留空格,紧跟左括号‘(’,以与关键字区别。
b.逗号与分号之后要留空格;“=”、“+=” “>=”、“<=”、“+”、“*”、“%”、“&&”、“||”、“<<”,“^”等二元操作符的前后应当加空格一元操作符前后不加空格
c.象“[]”、“.”、“->”这类操作符前后不加空格。
d.对于表达式比较长的for 语句和if 语句,为了紧凑起见可以适当地去掉一些空格。

for (i=0; i<10; i++) // 良好的风格

长行拆分
代码行最大长度宜控制在70 至80 个字符以内。长表达式要在低优先级操作符处拆分成新行,操作符放在新行之首(以便突出操作符)。拆分出的新行要进行适当的缩进,使排版整齐,语句可读。

if ((very_longer_variable1 >= very_longer_variable12)
    && (very_longer_variable3 <= very_longer_variable14)
    && (very_longer_variable5 <= very_longer_variable16))
{
    dosomething();
}

注释
a.注释是对代码的“提示”,而不是文档。程序中的注释不可喧宾夺主,注释太多了会让人眼花缭乱。注释的花样要少。
b.边写代码边注释,修改代码同时修改相应的注释,以保证注释与代码的一致性。不再有用的注释要删除。
c.尽量避免在注释中使用缩写,特别是不常用缩写。
d.注释的位置应与被描述的代码相邻,可以放在代码的上方或右方,不可放在下方。
f.当代码比较长,特别是有多重嵌套时,应当在一些段落的结束处加注释,便于阅读。
类的版式
类的版式主要有两种方式:
(1)将private 类型的数据写在前面,而将public 类型的函数写在后面。采用这种版式的程序员主张类的设计“以数据为中心”,重点关注类的内部结构。
(2)将public 类型的函数写在前面,而将private 类型的数据写在后面。采用这种版式的程序员主张类的设计“以行为为中心”,重点关注的是类应该提供什么样的接口(或服务)。
建议读者采用“以行为为中心”的书写方式,即首先考虑类应该提供什么样的函数。

class A
{
    public:
        void Func1(void);
        void Func2(void);
        …
    private:
        int i, j;
        float x, y;
        …
}

共性规则
a.标识符应当直观且可以拼读,可望文知意;标识符的长度应当符合“min-length && max-information”原则。
b.命名规则尽量与所采用的操作系统或开发工具的风格保持一致。
例如 Windows 应用程序的标识符通常采用“大小写”混排的方式,如AddChild。而Unix 应用程序的标识符通常采用“小写加下划线”的方式,如add_child。别把这两类风格混在一起使用。
c.变量的名字应当使用“名词”或者“形容词+名词”;全局函数的名字应当使用“动词”或者“动词+名词”(动宾词组)。
d.尽量避免名字中出现数字编号,如Value1,Value2 等,除非逻辑上的确需要编号。这是为了防止程序员偷懒,不肯为命名动脑筋而导致产生无意义的名字(因为用数字编号最省事)。
简单的Windows 应用程序命名规则
a.类名和函数名用大写字母开头的单词组合而成
b.变量和参数用小写字母开头的单词组合而成。
c.常量全用大写的字母,用下划线分割单词。
d.静态变量加前缀s_(表示static)。
e.如果不得已需要全局变量,则使全局变量加前缀g_(表示global)。
f.类的数据成员加前缀m_(表示member),这样可以避免数据成员与成员函数的参数同名。
g.为了防止某一软件库中的一些标识符和其它软件库中的冲突,可以为各种标识符加上能反映软件性质的前缀。
if语句
不可将浮点变量用“==”或“!=”与任何数字比较。

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

有时候我们可能会看到 if (NULL == p) 这样古怪的格式。不是程序写错了,是程序员为了防止将 if (p == NULL) 误写成 if (p = NULL),而有意把p 和NULL 颠倒。编译器认为 if (p = NULL) 是合法的,但是会指出 if (NULL = p)是错误的,因为NULL不能被赋值。
程序中有时会遇到 if/else/return 的组合,应该将如下不良风格的程序

if (condition)
    return x;
return y;

改写为

if (condition)
{
    return x;
}
else
{
    return y;
}

或者改写成更加简练的

return (condition ? x : y);

循环语句的效率
C++/C 循环语句中,for 语句使用频率最高,while 语句其次,do 语句很少用。提高循环体效率的基本办法是降低循环体的复杂性。
在多重循环中,如果有可能,应当将最长的循环放在最内层,最短的循环放在最外层,以减少CPU 跨切循环层的次数。
switch 语句
不要忘记最后那个default 分支。即使程序真的不需要default 处理,也应该保留语句 default : break; 这样做并非多此一举,而是为了防止别人误以为你忘了default 处理。
goto 语句
我们主张少用、慎用goto 语句,而不是禁用。
const 与 #define 的比较
C++ 语言可以用const 来定义常量,也可以用 #define 来定义常量。但是前者比后者有更多的优点:
(1)const 常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查。而对后者只进行字符替换,没有类型安全检查,并且在字符替换可能会产生意料不到的错误(边际效应)。
(2)有些集成化的调试工具可以对const 常量进行调试,但是不能对宏常量进行调试。
建议:在C++ 程序中只使用const 常量而不使用宏常量。
类中的常量
有时我们希望某些常量只在类中有效。由于#define 定义的宏常量是全局的,不能达到目的,于是想当然地觉得应该用const 修饰数据成员来实现。const 数据成员的确是存在的,但其含义却不是我们所期望的。const 数据成员只在某个对象生存期内是常量,而对于整个类而言却是可变的,因为类可以创建多个对象,不同的对象其const 数据成员的值可以不同。不能在类声明中初始化const 数据成员。以下用法是错误的,因为类的对象未被创建时,编译器不知道SIZE 的值是什么。

class A
{
    …
    const int SIZE = 100; // 错误,企图在类声明中初始化const 数据成员
    int array[SIZE]; // 错误,未知的SIZE
};

const 数据成员的初始化只能在类构造函数的初始化表中进行,例如

class A
{
    …
    A(int size); // 构造函数
    const int SIZE ;
};
A::A(int size) : SIZE(size) // 构造函数的初始化表
{
    …
}
A a(100); // 对象 a 的SIZE 值为100
A b(200); // 对象 b 的SIZE 值为200

怎样才能建立在整个类中都恒定的常量呢?别指望const 数据成员了,应该用类中的枚举常量来实现。例如

class A
{
    …
    enum { SIZE1 = 100, SIZE2 = 200}; // 枚举常量
    int array1[SIZE1];
    int array2[SIZE2];
};

枚举常量不会占用对象的存储空间,它们在编译时被全部求值。枚举常量的缺点是:它的隐含数据类型是整数,其最大值有限,且不能表示浮点数(如PI=3.14159)。

免责声明:文章转载自《高质量C++/C 编程指南一》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇问题:C#控制台 停留;结果:c#控制台如何延时显示mac终端下ssh虚拟机中的linux提示WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

菜鸟学STM32之跑马灯

微信公众号:小樊Study关注共同学习,问题或建议,请公众号留言!!! 作为一名程序员,在初步学习编程想必都绕不开一个最为基础的入门级示例“Hello World”,那么,在学习单片机时,最基础的入门示例是什么呢?没错,那就是“点亮一盏LED灯”本次将通过一个经典的跑马灯程序,带大家开启 STM32F4 之旅,通过本次的学习,你将了解到 STM32F4 的...

CentOS7 初始化配置

一、在安装的时候配置网卡名称的参数 1. 选择“Install Centos 7” 2. 按Tab,打开kernel启动选项后,增加 net.ifnames=0 biosdevname=0 二、最小化安装完成之后必备安装软件 # 添加epel源,安装基础软件,设置主机名rpm -ivh http://mirrors.aliyun.com/epel/epe...

如何用webpack搭建vue项目?本文案例详解

前言:都2020年了,感觉是时候该学一波webpack了,趁着最近有时间,就学了一下,等把官网上的webpack结构和模块大概看了一遍之后,就感觉可以开始搭个项目实战一下了,从0开始,一步步记录下来 使用版本: webpack4.x 1.包含插件和loader * html: html-webpack-plugin clean-webpack...

iOS 架构-App组件化开发

前因 其实我们这个7人iOS开发团队并不适合组件化开发。原因是因为性价比低,需要花很多时间和经历去做这件事,带来的收益并不能彻底改变什么。但是因为有2~3个星期的空档期,并不是很忙;另外是可以用在一个全新的App上。所以决定想尝试下组件化开发。 所谓尝试也就是说:去尝试解决组件化开发当中的一些问题。如果能解决,并且有比较好的解决方案,那就继续下去,否则就...

electron 显示对话框 showMessageBoxSync showMessageBox

7.3.2的文档:https://github.com/electron/electron/blob/v7.3.2/docs/api/dialog.md 不同版本可以切换 一个是同步对话框,另外一个是异步。 同步: win.webContents.on('xxx-event', (event) =>{ console.log("==cust_...

STM32 OLED屏显示详解

不多废话,先看效果         全家福 观看演示效果: https://www.bilibili.com/video/BV13V411b78V 一、基础认识及引脚介绍 屏幕参数: 尺寸:0.96英寸 分辨率:128*64 驱动芯片:SSD1306 驱动接口协议:SPI 引脚说明: 二、 SSD1306芯片介绍 SSD1306是一款带控制器的用于OL...