《高质量 C++/C 编程指南》笔记

林锐博士著,v1.0,2001-07-24 定稿。原为航天信息股份有限公司科研计划项目产物,是国内早期影响极大的 C/C++ 编码规范文档,也是微软 Asia 技术中心等机构的参考规范。全书 101 页,含课程设计与参考答案(附录 A/B 为笔试/上机样题)。

全书结构

  • 第 1-6 章:编程风格(难度不高、细节多)——文件结构、程序版式、命名规则、表达式和基本语句、常量、函数设计
  • 第 7-11 章:专题论述(技术难度高)——内存管理、C++ 函数高级特性、类的构造函数/析构函数/赋值函数、类的继承与组合、其它编程经验

核心观点

1. 代码风格是专业性的体现

  • “程序是写给人读的,只是偶尔让计算机执行一下”
  • 版式规则:空行划分逻辑块、代码行缩进 4 空格、指针 * 属于变量(char *p; 而非 char* p;,避免 char* a, b; 的误解)、长行在低优先级操作符处拆分且续行对齐
  • 命名:数组名用复数(student_array),函数名用动宾词组(GetStudentName),禁止含义不清的命名如 Flag、Data1
  • 注释规则:注释与代码”同步”才有效,半个错误注释比没有更糟;/*流式注释*/ 风格优于 //(C++ 程序员用 // 会被误认为 C++ 新手写 C)

2. 表达式与基本语句的经典陷阱

  • if (x = 0) 赋值误用:比较时应写成 if (0 == x)(Yoda 条件)
  • if ((min < A) && (A < max)) 写法错误——C/C++ 中 min < A < max 恒为真
  • switch 每个 case 必须以 break 结束
  • do { ... } while(condition); 分号不能漏
  • 减少循环体内语句量:把不变量提到循环外(如 for (i = n*(j+k); ...))

3. 函数设计契约

  • 参数校验在函数入口用 assert;断言只在调试阶段生效,Release 版自动失效,不能再断言中写执行语句
  • 指针释放后立即置 NULL,防止”野指针”
  • 函数功能内聚:一个函数只干一件事
  • 返回值为指针或引用时,检查是否返回了”栈内存地址”或”已经free的堆内存”(悬垂指针)
  • 避免函数参数过多;输入参数加 const 保护

4. 内存管理(全书精华章)

  • 三种内存分配:静态存储区(全局/static)、栈(自动释放、容量有限、效率极高)、堆(malloc/new,灵活但问题最多)
  • 常见内存错误及对策:
    • 分配未使用即引用 → 入口 assert(p!=NULL) 或 if(p==NULL) 防错
    • 未初始化就引用 → 内存缺省初值没有统一标准,宁可信其无;数组永远显式赋初值
    • 越界 → for 循环次数”多 1 / 少 1”是惯犯
    • 内存泄漏 → 申请与释放配对;“不是每次必现的泄漏最可怕”
    • 释放后仍引用(free 后不置 NULL 的野指针)
  • malloc(0) 与 new 失败返回:malloc(0) 返回非 NULL 的”最小内存块”指针,operator new 失败抛异常——new 应写 new(nothrow) 才返回 NULL,所以 if(p==NULL) 式的 new 防错默认不成立
  • 二维动态数组的四种正确写法(含一级指针数组、二级指针、一维连续)
  • 引用与指针的区别:引用一旦初始化不可更改、无空引用(但仍会有”空引用”,即 &(*NULL) 这种引用空指针的非法操作)

5. C++ 类的三大件(构造/析构/赋值)

  • 如果类没有声明这三样,编译器自动生成默认版本
  • 赋值函数必须:①检查自赋值 ②delete 原有资源 ③拷贝 ④返回 *this
  • 析构函数禁止抛异常
  • 构造函数调用虚函数不会有多态效果
  • 拷贝构造与赋值函数的区别在”对象是否已存在”

6. 继承与组合的准则

  • 多用组合、慎用继承(“public 继承是一种 is-a 关系”,只有真 is-a 才继承)
  • 派生类的析构/拷贝会先调用基类对应函数
  • 只有基类的 virtual 函数才有覆写意义;避免遮蔽(overwriting)同名非虚函数

7. 其它编程经验

  • 慎用全局变量、慎用 goto、慎用类型转换
  • 宏定义技巧:参数和外层都加括号 #define SQUARE(x) ((x)*(x)),且宏名全大写
  • 变量声明的位置要靠近使用处,作用域越小越好
  • 运算符优先级记不清就加括号

经典面试样题(附录 A)

  • 写出 BOOL 与”零值”比较的 if 语句:if(!bTestFlag)
  • 写出 float 与零值比较:if((f >= -EPSINON) && (f <= EPSINON))(不能 f == 0.0)
  • 指针与零值比较:if(p == NULL)
  • sizeof(p)(数组名作参数退化为指针):题目中 sizeof(p) 恒为 4(32 位平台指针宽度)
  • strcpy 标准实现及为何返回 char*:为实现链式表达式 strlen(strcpy(dst, src))
  • 手写 String 类四大件(本书标准答案见上文规则)

可行动点

  • 作为 C/C++ 代码 review 检查单:本文”表达式陷阱”和”内存错误”清单可直接用于 review 清单
  • “三大件”模板可直接抄入新写的 C++03 风格裸管理类
  • 对新人培训仍是有效材料(风格部分不因 C++11/17 过时;内存部分被 RAII/智能指针部分取代——第 7 章的教训在智能指针时代仍适用于裸指针边界)

关联

元信息

  • 云盘路径:/田浩然上传的资料/1A004_C++程序设计/参考资料/C C++高质量编程.pdf(101 页,326 KB)
  • 版本:v1.0 正式文件,2001-07-24
  • 提取方式:pdftotext 兜底(pdf-inspector 判 text_based 但 markdown 输出为空,疑似字体编码自定义映射)