Chinaunix首页 | 论坛 | 博客
  • 博客访问: 596894
  • 博文数量: 119
  • 博客积分: 6010
  • 博客等级: 准将
  • 技术积分: 1583
  • 用 户 组: 普通用户
  • 注册时间: 2008-08-15 09:18
文章分类

全部博文(119)

文章存档

2011年(3)

2010年(21)

2009年(44)

2008年(51)

我的朋友

分类: C/C++

2008-08-20 14:56:07

今天开始读《高质量C++编程指南》一书,我每天都会把读到的知识总结进来,以便以后查阅.
 
一:
1.对于C及C++的头文件的版权说明格式.
  /*
  *Corpyright (c) 2008 北京**有限公司
  *All rights reserved.
  *文件名称:main.h
  *文件标识:
  *摘    要:定义系统硬件资源
 
  *当前版本:1.0
  *作   者:**
  *完成日期:08年8月20日
  *取代版本:无
  *原作者  :**
  *完成日期:
  */
2.对于头文件
  1)防止重复引用要用ifndef/define/endif来产生预处理快.
  2)用include<**.h>来引用标准库文件(编译器将从标准库里开始查找).用include"**.h"用来引用非标准文件(编译器将从用户目录开始查找).//应该是编译器连接速度快.
  3)头文件只"声明"不"定义".//避免重复定义.
 
举例说明:
________________________________________________________________________
#ifndef GRAPHICS_H // 防止graphics.h 被重复引用
#define GRAPHICS_H
#include // 引用标准库的头文件

#include “myheader.h” // 引用非标准库的头文件

void Function1(⋯); // 全局函数声明

class Box // 类结构声明
{

};
#endif
________________________________________________________________________
 
二:
1.空行
   1)在每个类声明之后、每个函数定义结束之后都要加空行。􀁺
   2在一个函数体内,逻揖上密切相关的语句之间不加空行,其它地方应加空行分隔。
 
1)例子
________________________________________________________________________
// 空行
void Function1(⋯)
{

}
// 空行
void Function2(⋯)
{

}
// 空行
void Function3(⋯)
{
}
// 空行
_________________________________________________________________________
2)例子
_________________________________________________________________________
while (condition)
{
statement1;
// 空行
if (condition)
{
statement2;
}
else
{
statement3;
}
// 空行
statement4;
}
___________________________________________________________________________
 
2.代码行:
  1)一行代码只做一件事情,如只定义一个变量,或只写一条语句。这样的代码容易阅读,并且方便
于写注释。   
  2)if、for、while、do 等语句自占一行,执行语句不得紧跟其后。不论执行语句有多少都要加
{}。这样可以防止书写失误。   
 
例子
好习惯____________________________________________________________________________
int width; // 宽度
int height; // 高度
int depth; // 深度
int width, height, depth; // 宽度高度深度
x = a + b;
y = c + d;
z = e + f;
X = a + b; y = c + d; z = e + f;
if (width < height)
{
dosomething();
}
坏习惯_____________________________________________________________________________
if (width < height) dosomething();
for (initialization; condition; update)
{
dosomething();
}
// 空行
other();
for (initialization; condition; update)
dosomething();
other();
_________________________________________________________________________________  
3)尽可能在定义变量的同时初始化该变量(就近原则)
3.代码行内的空格
  1)关键字之后要留空格。象const、virtual、inline、case 等关键字之后至少要留一个空格,否
则无法辨析关键字。象if、for、while 等关键字之后应留一个空格再跟左括号‘(’,以突出关键字。
  2)函数名之后不要留空格,紧跟左括号‘(’,以与关键字区别。
  3)‘(’向后紧跟,‘)’、‘,’、‘;’向前紧跟,紧跟处不留空格。
  4)‘,’之后要留空格,如Function(x, y, z)。如果‘;’不是一行的结束符号,其后要留空格,
如for (initialization; condition; update)。
  5)赋值操作符、比较操作符、算术操作符、逻辑操作符、位域操作符,如“=”、“+=” “>=”、
“<=”、“+”、“*”、“%”、“&&”、“||”、“<<”,“^”等二元操作符的前后应当加空格。
  6)一元操作符如“!”、“~”、“++”、“--”、“&”(地址运算符)等前后不加空格。
  7)象“[]”、“.”、“->”这类操作符前后不加空格。
  8)】对于表达式比较长的for 语句和if 语句,为了紧凑起见可以适当地去掉一些空格,如for (i=0; i<10; i++)和if ((a<=b) && (c<=d))
 
例子
_________________________________________________________________________________
 
void Func1(int x, int y, int z); // 良好的风格
void Func1 (int x,int y,int z); // 不良的风格
if (year >= 2000) // 良好的风格
if(year>=2000) // 不良的风格
if ((a>=b) && (c<=d)) // 良好的风格
if(a>=b&&c<=d) // 不良的风格
for (i=0; i<10; i++) // 良好的风格
for(i=0;i<10;i++) // 不良的风格
for (i = 0; I < 10; i ++) // 过多的空格
x = a < b ? a : b; // 良好的风格
x=aint *x = &y; // 良好的风格
int * x = & y; // 不良的风格
array[5] = 0; // 不要写成 array [ 5 ] = 0;
a.Function(); // 不要写成 a . Function();
b->Function(); // 不要写成 b -> Function();
_________________________________________________________________________________
 
4.对齐
   1)程序的分界符‘{’和‘}’应独占一行并且位于同一列,同时与引用它们的语句左对齐。 
   2){ }之内的代码块在‘{’右边数格处左对齐。
 
例子:
 
_________________________________________________________________________________
 
void Function(int x)     良好风格
{
 // program code
}
void Function(int x){     不良风格
 // program code
}
if (condition)            良好风格
{
 // program code
}
else
{
 // program code
}
if (condition){          不良风格
 // program code
}
else {
 // program code
}
for (initialization; condition; update)      良好风格
{
 // program code
}
for (initialization; condition; update){     不良风格
 // program code
}
While (condition)                            良好风格
{
 // program code                       
}
while (condition){                           不良风格
 // program code
}
如果出现嵌套的{},则使用缩进对齐,如:
{
    {

    }
}
_________________________________________________________________________________
 
5.长行拆分
 
  1)代码行最大长度宜控制在70 至80 个字符以内。代码行不要过长,否则眼睛看不过来,也不便于打印。
  2)长表达式要在低优先级操作符处拆分成新行,操作符放在新行之首(以便突出操作符)。拆分出的新行要进行适当的缩进,使排版整齐,语句可读。
 
例子
_________________________________________________________________________________
 
if ((very_longer_variable1 >= very_longer_variable12)
&& (very_longer_variable3 <= very_longer_variable14)
&& (very_longer_variable5 <= very_longer_variable16))
{
dosomething();
}
virtual CMatrix CMultiplyMatrix (CMatrix leftMatrix,
CMatrix rightMatrix);
for (very_longer_initialization;
very_longer_condition;
very_longer_update)
{
dosomething();
}
_________________________________________________________________________________
 
6.修饰符位置

  修饰符 * 和 & 应该靠近数据类型还是该靠近变量名,是个有争议的活题。
若将修饰符 * 靠近数据类型,例如:int* x; 从语义上讲此写法比较直观,即x
是int 类型的指针。
上述写法的弊端是容易引起误解,例如:int* x, y; 此处y 容易被误解为指针变
量。虽然将x 和y 分行定义可以避免误解,但并不是人人都愿意这样做。
􀁺 【规则2-6-1】应当将修饰符 * 和 & 紧靠变量名
例如:
char *name;
int *x, y; // 此处y 不会被误解为指针

7.注释

    C 语言的注释符为“/*…*/”。C++语言中,程序块的注释常采用“/*…*/”,行注
释一般采用“//…”。注释通常用于:
(1)版本、版权声明;
(2)函数接口说明;
(3)重要的代码行或段落提示。
虽然注释有助于理解代码,但注意不可过多地使用注释

   1)注释是对代码的“提示”,而不是文档。程序中的注释不可喧宾夺主,注释太多了
会让人眼花缭乱。注释的花样要少。

   2)如果代码本来就是清楚的,则不必加注释。否则多此一举,令人厌烦。例如
i++; // i 加 1,多余的注释.

   3)边写代码边注释,修改代码同时修改相应的注释,以保证注释与代码的一致性。不再
有用的注释要删除。

   4)注释应当准确、易懂,防止注释有二义性。错误的注释不但无益反而有害。

   5)尽量避免在注释中使用缩写,特别是不常用缩写。

   6)注释的位置应与被描述的代码相邻,可以放在代码的上方或右方,不可放在下方。

   7)当代码比较长,特别是有多重嵌套时,应当在一些段落的结束处加注释,便于阅读。

例子
____________________________________________________________________

/*
* 函数介绍:
* 输入参数:
* 输出参数:
* 返回值 :
*/
void Function(float x, float y, float z)
{

}
if (…)
{

while (…)
{

} // end of while

} // end of if

____________________________________________________________________

..........................................................

..........................................................略

8.循环语句的效率:

9.关于sizeof():

    用运算符sizeof 可以计算出数组的容量(字节数)。示例7-3-3(a)中,sizeof(a)
的值是12(注意别忘了’\0’)。指针p 指向a,但是sizeof(p)的值却是4。这是因为
sizeof(p)得到的是一个指针变量的字节数,相当于sizeof(char*),而不是p 所指的内
存容量。C++/C 语言没有办法知道指针所指的内存容量,除非在申请内存时记住它。
注意当数组作为函数的参数进行传递时,该数组自动退化为同类型的指针。示例
7-3-3(b)中,不论数组a 的容量是多少,sizeof(a)始终等于sizeof(char *)。

例子7-3-3(a)

_______________________________________________________________________

char a[] = "hello world";
char *p = a;
cout<< sizeof(a) << endl; // 12 字节
cout<< sizeof(p) << endl; // 4 字节

________________________________________________________________________

例子7-3-3(b)

________________________________________________________________________

void Func(char a[100])
{
cout<< sizeof(a) << endl; // 4 字节而不是100 字节
}

________________________________________________________________________

10.指针参数的传递
   1)如果函数的参数是一个指针,不要指望用该指针去申请动态内存。示例7-4-1 中,
Test 函数的语句GetMemory(str, 200)并没有使str 获得期望的内存,str 依旧是NULL,
为什么?
 
例子
 
___________________________________________________________________________________
 

void GetMemory(char *p, int num)
{
    p = (char *)malloc(sizeof(char) * num);
}
void Test(void)
{
    char *str = NULL;
    GetMemory(str, 100); // str 仍然为 NULL
    strcpy(str, "hello"); // 运行错误
}

___________________________________________________________________________________
 
毛病出在函数GetMemory 中。编译器总是要为函数的每个参数制作临时副本,指针
参数p 的副本是 _p,编译器使 _p = p。如果函数体内的程序修改了_p 的内容,就导致
参数p 的内容作相应的修改。这就是指针可以用作输出参数的原因。在本例中,_p 申请
了新的内存,只是把_p 所指的内存地址改变了,但是p 丝毫未变。所以函数GetMemory
并不能输出任何东西。事实上,每执行一次GetMemory 就会泄露一块内存,因为没有用
free 释放内存。
如果非得要用指针参数去申请内存,那么应该改用“指向指针的指针”,见示例7-4-2。
 
例子
___________________________________________________________________________________
 
void GetMemory2(char **p, int num)
{
    *p = (char *)malloc(sizeof(char) * num);
}
void Test2(void)
{
    char *str = NULL;
    GetMemory2(&str, 100); // 注意参数是 &str,而不是str
    strcpy(str, "hello");
    cout<< str << endl;
    free(str);
}
___________________________________________________________________________________
 
由于“指向指针的指针”这个概念不容易理解,我们可以用函数返回值来传递动态
内存。这种方法更加简单,见示例7-4-3。
 
例子
___________________________________________________________________________________
 
char *GetMemory3(int num)
{
    char *p = (char *)malloc(sizeof(char) * num);
    return p;
}
void Test3(void)
{
    char *str = NULL;
    str = GetMemory3(100);
    strcpy(str, "hello");
    cout<< str << endl;
    free(str);
}
___________________________________________________________________________________
 
用函数返回值来传递动态内存这种方法虽然好用,但是常常有人把return 语句用错
了。这里强调不要用return 语句返回指向“栈内存”的指针,因为该内存在函数结束时
自动消亡,见示例7-4-4。
 
例子
___________________________________________________________________________________
 
char *GetString(void)
{
    char p[] = "hello world";
    return p; // 编译器将提出警告
}
void Test4(void)
{
    char *str = NULL;
    str = GetString(); // str 的内容是垃圾
    cout<< str << endl;
}
___________________________________________________________________________________
 
用调试器逐步跟踪Test4,发现执行str = GetString 语句后str 不再是NULL 指针,
但是str 的内容不是“hello world”而是垃圾。
 
例子
__________________________________________________________________________________
 
char *GetString2(void)
{
    char *p = "hello world";
    return p;
}
void Test5(void)
{
    char *str = NULL;
    str = GetString2();
    cout<< str << endl;
}
___________________________________________________________________________________
 
函数Test5 运行虽然不会出错,但是函数GetString2 的设计概念却是错误的。因
为GetString2 内的“hello world”是常量字符串,位于静态存储区,它在程序生命期
内恒定不变。无论什么时候调用GetString2,它返回的始终是同一个“只读”的内存块。
 
11.一些有益的建议
 
  1)当心那些视觉上不易分辨的操作符发生书写错误。我们经常会把“==”误写成“=”,象“||”、“&&”、“<=”、“>=”这类符号也很容易发生“丢1”失误。然而编译器却不一定能自动指出这类错误。
 
  2)变量(指针、数组)被创建之后应当及时把它们初始化,以防止把未被初始化的变量当成右值使用。
  3)当心变量的初值、缺省值错误,或者精度不够。
  4)当心数据类型转换发生错误。尽量使用显式的数据类型转换(让人们知道发生了什么事),避免让编译器轻悄悄地进行隐式的数据类型转换。
 
  5)当心变量发生上溢或下溢,数组的下标越界。
  6)当心忘记编写错误处理程序,当心错误处理程序本身有误。
  7)当心文件I/O 有错误。
  8)避免编写技巧性很高代码。
  9)不要设计面面俱到、非常灵活的数据结构。
 10)如果原有的代码质量比较好,尽量复用它。但是不要修补很差劲的代码,应当重新编写。
 11)尽量使用标准库函数,不要“发明”已经存在的库函数。
 12)尽量不要使用与具体硬件或软件环境关系密切的变量。
 13)把编译器的选择项设置为最严格状态。
 14)如果可能的话,使用PC-Lint、LogiScope 等工具进行代码审查。
阅读(885) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~