现在的位置: 首页 > 综合 > 正文

《高质量程序设计指南——C/C++》第6章 C/C++函数设计基础

2013年09月14日 ⁄ 综合 ⁄ 共 2206字 ⁄ 字号 评论关闭

第6章 C/C++函数设计基础

6.1 认识函数
   1、函数对于构建程序并不是必需的,但却是非常重要的,它极大的增强了代码的模块性,使程序更易于开发和维护。
   2、在程序中积极的使用现有的库不仅可以节省时间,还可以提高程序的质量。
   3、关于静态链接库和动态链接库:
       写了这么久的代码,关于“静态链接库”和“动态链接库”的概念,一直很模糊。刚才百度了一下,摘录如下:
静态链接库是 *.lib 格式的文件,一般在工程的设置界面中加入工程,程序“编译时”会把lib文件的代码加入到你的程序中,因此会增加代码大小,你的程序一开始运行,lib代码强制被装入你程序的运行空间,不能手动移除lib代码。

动态链接库是程序“运行时”动态装入内存的模块,格式*.dll,在程序运行时可以随意加载和移除,节省内存空间。在大型的软件项目中一般要实现很多功能,如果把所有单独的功能写成一个个*.lib文件的话,程序运行的时候要占用很大的内存空间,导致运行缓慢;但是如果将功能写成*.dll文件,就可以在用到该功能的时候调用功能对应的dll文件,不用这个功能时将dll文件移除内存,这样可以节省内存空间”。

     看完这段话,似乎又理解得多一点了。
   
     如果程序中任何地方都没有调用你自己编写的某个函数的话,编译器也不会为该函数生成可执行代码。 ---- 一直不明白的道理,今天看到了。呵呵,收获!这样的话,我们在开发一些通用类的时候,应该设计并实现其完整的功能,而不必担心它的使用者仅使用其中一小部分的功能,却要包含整个类定义而会导致代码体积增大。C++模版实例化及类库的设计和实现就是这个道理。

6.2 函数原型和定义

1、函数原型的格式如下:
[作用域][函数的链接规范] 返回值类型 [函数的调用规范] 函数名(形参列表...);
这个格式有点晕!以前对函数原型的印象好像就是 返回值类型 函数名(形参列表...);
这个差异留待以后慢慢体会理解吧。

2、理解形参和实参的区别:函数调用中参数传递的本质就是“用实参初始化形参”而不是替换形参,记住这一点很重要!

6.3 函数调用方式
6.4 函数堆栈
6.5 函数调用规范(Calling Convention)
    函数调用规范?又一个新鲜玩意儿!没有用过。
Windows环境下常用的调用规范有:
1) _cdecl
2) _stdcall
3) _thiscall
4) _fastcall

6.6 函数链接规范(Linkage Specification)
      在使用不同编程语言进行软件联合开发的时候,需要统一函数、变量、数据类型、常量等的连接规范,特别是在不同模块之间共享的接口部分。

6.7 函数参数传递规则
      函数接口的两个要素是参数和返回值。
      C语言中,函数的参数和返回值的传递方式有两种:pass by value 和 pass by pointer.
      C++语言中,除了pass by value 和 pass by pointer外,还增加了一种pass by reference.
      有两个好的编码建议:
1)如果参数是指针,且仅做输入用,则应该在类型前加const,以防止该指针指向的内存单元(指针指向的值或内容)在函数体内被无意的修改。
2)避免函数有太多的参数(建议小于5个)。如果有太多的参数,则考虑重构:封装为一个对象。

6.8 函数返回值的规则
    函数返回值有两种途径:一是使用return语句;二是使用输出参数。
1、不要将正常值和错误标志混在一起返回。例如可以将正常值用输出参数返回,而错误标志用return语句返回。反之亦可,具体情况具体对待。
2、不要把函数的返回值用作左值!!

6.9 函数内部实现的规则
程序设计中很大部分精力在实现函数(即定义函数实现)。因此,谨慎而严密的定义函数实现对提高软件质量尤为重要。
我们可以在函数体的“入口处”和“出口处”严格把关.
1) 在函数体的入口处,对参数的有效性进行检查。大量使用断言(assert)。
2) 在函数的出口处,对return语句的正确性和效率进行检查。
3) 当然,不仅要检查输入参数的有效性,还要检查通过其它途径(成员变量或全局变量)进入函数体内的变量的有效性。
4) static 局部变量的一个有效利用:可以实现全局变量的封装。例如:
inline const char* GetWindowsPath(void)
{
    static const char *p = "C:\\Windows\\";
    return p;
}

6.10 存储类型及作用域规则
     读完这一节,脑子里有点乱。先不整理了,用到或遇到问题时再查阅吧。

6.11 递归函数
     递归函数具有“天然的低效率”。但是递归能使某些问题直观简洁。

6.12 使用断言(assert)
     使用断言的目的:捕捉在运行时不该发生的“非法情况”。这里就得区分“非法情况”与“错误情况”的区别了。
举个例子:
assert(i == 1);
就是你必须确信i必须为1,要是为别的值就直接结束程序了。

1)非法情况就是出现了某个情况,程序就应该直接退出,而不是返回那么简单。
2)错误情况即出现了错误输入或操作,程序应该做出处理:
1)修正输入或改正操作。
2)直接返回,提示用户输入或操作有误。

6.12 使用const提高函数的健壮性
"Use const whenever you need."
在使用const修饰函数的返回值时,需要多一点思考。

抱歉!评论已关闭.