一 程序的设计

  要避免错误,首先要从好的设计开始。对于程序的设计,需考虑到程序的两个特性:

  1简单性

  大多数常见的错误来源于程序设计中不必要的复杂成分。一个好的设计应该反映问题本身的要求,而不必为了刻意追求“满足将来的需要”而添加不必要的特性。实际上,简单优雅的设计比那些复杂的设计更能迎合未来的需求。

  2 耦合性

  耦合(decoupling)性用来衡量不同对象之间的依赖程度。松耦合的程序易于理解和实现,易于测试和维护,且这种程序包含错误的可能性小,错误也较容易发现和清除。

二 编程风格

  编程风格是个人问题,有很大的随意性。一个好的编程风格不仅让代码易理解,也易于调试。好的编程风格包括:

  1 清晰地书写代码

  如果没有必要,尽量不要使用语言中的高级特性,因为这些特性不易于理解和调试。使用大多数程序员都能理解的语言成分来书写代码不易犯错且易于理解和维护。

  2 编写结构良好的代码

  当程序崩溃时所能得到的最基本的调试信息是源代码文件、问题所在行的行号和一个调用栈(call stack)。调用栈是调试程序时最有帮助的部分,它提供错误出现的上下文,也就是带参数的函数调用序列。你书写的代码结构越好,调用栈就能给你越多信息。

  3 使用良好的标识符

  一个好名字能使你的代码更容易被理解和维护。流行的匈牙利命名法(Hungarian Notation)实际上是把标识符的意义和表示方法结合起来。现在,匈牙利命名法表现出不少的局限性,匈牙利命名法过于看重前缀的作用,对一个变量的表达信息不完整,实际上并没有传递多少有用信息,它使代码难于阅读,难以维护。一个好的命名传统是指示出变量的作用域以便在需要的时候检查它的定义,并明确地指出一个变量是全局的、局部的还是成员数据。依赖变量的定义比依赖匈牙利前缀更加有用和可靠。

  好的名字能够用平常的语言概括出该标识符所代表的实体的含义。在选择类、函数、变量的名字时可以考虑以下几个原则:

    取简单的描述性名字,好的名字能简要地概括出这个标识符代表的含义。

    避免简写,简写使标识符难于阅读和记忆,尽量使用混合大小写的完整的单词。

    避免相似性的文字,避免混淆。

    避免采用一般的或随机产生的名字,而应采用有实际意义的名字。如欲从按钮类派生位图按钮,取一个CBitmapButton,而不是CMyButton。

  4 用简单的语句行

  在VC中,一行可写多个语句。但调试是面向行的,过于复杂的行难于调试。因此,从调试的角度出发,每一个语句都应独自成行。

  5 使用统一的排列

  统一的排列方式使类、变量的定义和语句更加明显。

  6 用括号使书写清晰

  你不一定能都记住各种运算符的优先级和结合律,而使用多余的括号并不影响编译后的代码。因此,如果你不能确定是否需要括号时,请加上它。

  7 使用好的注释

  用好的注释能使你的代码不易出错,而且便于其他程序员阅读,便于理解和维护。

三 编写程序时应注意的问题

  1 充分利用VC++的特性

  可用下列技术来充分利用VC++的编译器的特性:

  (1)用const代替#define来创建常量;

  (2)用enum代替#define来创建常量集合;

  (3)用内联(inline)函数代替#define;

  这三种技术用C++而不是C预处理。使用预处理的问题在于编译器对于预处理器所作的事情一无所知,因此无法用数据类型检查错误和不一致的地方。预处理的名字不在符号表里,因此也不能用调试工具来检查预处理常量。相似地,预处理宏被编译进去,不能用调试工具跟踪。编译器能充分了解const、enum和inline语句,从而能在编译的时候对出现的问题发出警告。

  但预处理在很多调试代码中起重要作用。调试代码经常需要从非调试代码里面得到不同的行为,而最有效的办法就是让预处理为调试创建不同的代码。

  (4)用new和delete代替malloc和free;

  在创建对象、类型的安全性和灵活性方面。使用new/delete比malloc/free要好。另外,new可被重载,提供了更大的灵活性。

  (5)用输入输出流(iostreams)代替stdio。

  使用C++输入输出流(<<和>>)而不使用C标准输入输出库(printf/sprintf和scanf/sscanf),有利于安全性和扩展性。从调试的角度来看,标准输入输出函数的最大问题在于编译器不能对控制流参数进行任何类型检测,而输入输出流的任何问题都能在编译时检测出来。

  2 使用头文件

  要在头文件中声明所有共享的外部符号,而且保留函数原型中的参数名。把所有的共享定义放在头文件中,不要在.cpp文件里面看到extern关键字。

  3 初始化变量

  在使用变量之前一定要把它们初始化。在初始化之前就使用变量肯定会产生错误。通常不需对对象进行初始化,对对数据成员应在构造函数中初始化。必须明确地为在栈中和堆中分配的数组和数据结构进行初始化。对于对象,应该初始化每个需要初始化的数据成员。因为变量的使用是由优化器来检查的,所以检测未初始化的本地变量,发布版本要比调试版本要做得好。

  4 使用布尔表达式

C++的布尔类型:bool,值为true和false,大小为一个字节。

Windows程序通常用BOOL类型。定义如下:

Typedef int BOOL;

#define FALSE 0

#define TRUE 1

  在C++中,一个布尔表达式如果为0则为假,其他则为真。因此,对布尔表达式应该检查是否问假而不是检查是否为真。

  5 使用句柄和指针

  初始化一个指针时,要么让其指向一个有效的内存地址,要么设为0(空指针),避免指针指向无效地址。回收指针所指对象时要重新初始化这个指针,并且在指针被释放前为空时就对其进行处理。对句柄的处理跟指针一样。

  6 用引用而不是指针做参数

  用指针做函数的参数可传递一个空指针,很灵活,但也很容易忘了对指针进行初始化。而引用是对象的别名,它必须和有效的对象相关联,不存在空的和没有初始化的引用。当在函数中收到一个引用参数时,可以肯定这是一个有效的对象。程序用引用做参数比用指针做参数更为健壮。

  7 强制类型转换(cast)

  进行数据类型的强制类型转换时,将会调用相应的构造函数或转换函数来创建一个新类型的临时对象。对指针的正确类型转换可消除一个编译错误,但并没改变指针。强制类型转换破坏了编译器进行类型检查的功能,而这正是编译器查找错误的最有效的机制。为了保证安全性,每一个强制类型转换都需要手工进行类型检查。为尽量避免强制类型转换,你可以:避免使用多态数据类型;使用更加广泛的基类;提供特殊的存取函数;让编译器隐式处理类型转换等措施。

  8 使用构造函数和析构函数

  构造函数需要分配内存,创建资源或者打开文件,这些运算并不总是成功。构造函数没有返回值,没有直接显示错误的方法。一个常见的方法(在很多MFC类中使用)是把对象创建分为两步:第一步,让构造函数以一种不会出错的方式初始化对象;第二步,让某些初始化函数(如Init或Open)完成工作,这一步可能出错。另一种方法是在构造函数中使用异常:第一步,以不会出错的方式初始化对象;第二步,用可能在try段内出错的代码初始化对象;第三步,在catch代码里面处理异常。如果出现异常,就会在构造函数里清除分配的资源,并且再次抛出异常。

  异常处理的一个关键细节就是在栈展开的过程中抛出的异常会终止整个应用程序。在处理异常时经常要调用析构函数,因此析构函数很容易出错,一定要保证析构函数的异常在析构函数中得到处理。要保证基类的析构函数是虚函数。这样,就算对象是一个指向基类的指针,也会调用派生类的析构函数。否则,就会引起资源泄漏(resource leak)。

更多技术文章请参看施昌权的个人网站: http://www.joyvc.cn

转载于:https://www.cnblogs.com/scq2099yt/archive/2008/03/10/1098457.html

编写易于调试的vc代码相关推荐

  1. VC代码的编写和调试---编写易于调试的VC代码

    转自:http://www.vcgood.com/forum_posts.asp?TID=1692&PN=1 一 程序的设计 要避免错误,首先要从好的设计开始.对于程序的设计,需考虑到程序的两 ...

  2. VC代码的编写和调试

    VC代码的编写和调试(转载) VC代码的编写和调试(转载) //========================================== // [转载声明] // 出自: // 作者:   ...

  3. 编写易于理解代码的六种方式

    http://www.ibm.com/developerworks/cn/linux/l-clear-code/ 我学习编写.改善和维护代码的过程是很艰苦的.在过去的 12 年里,我一直在编写计算机游 ...

  4. java在线支付---09,10,11,12_在线支付_分析易宝支付网关的应答协议与处理代码,完成用于处理支付响应的Servlet的初步编写和调试,完成处理支付网关响应结果的Servlet,支付实现

    09_在线支付_分析易宝支付网关的应答协议与处理代码 创梦综合技术qq交流群:CreDream:251572072 对支付结果返回的数据加密生成md5-hmac public static boole ...

  5. MATLAB中MEX文件的编写与调试

    *************************************************** 更多精彩,欢迎进入:http://shop115376623.taobao.com http:/ ...

  6. react 代码编写原则_如何编写易读的React代码— 10种编码风格技巧

    react 代码编写原则 by Nirmalya Ghosh 由Nirmalya Ghosh 如何编写易读的React代码- 10种编码风格技巧 (How to write highly readab ...

  7. MATLAB的MEX文件编写和调试

    资料一 MATLAB的MEX文件编写和调试 1. MEX的编写格式 写MEX程序其实就是写一个DLL程序,所以你可以使用C,C++,Fortran等多种编程语言来写. 编写MEX程序的编辑器可以使用M ...

  8. 【代码质量的重要性:如何编写具有高质量标准的代码】

    一. 前言 写出高质量的代码对于软件开发人员和整个团队都是非常重要的,因为它有以下几个方面的好处: 1. 提高代码可维护性:高质量的代码通常更易于理解和维护,因为它们更具有结构性和组织性. 2. 增加 ...

  9. 编写和调试Shader程序(1)

    编写和调试Shader程序 (1)DirectX EffectEdit JohnsonFeng 常用的Shader编写程序有ATI Render Monkey和NVIDIA FX Composer,另 ...

最新文章

  1. camelot工具进行pdf表格解析重建
  2. html标签教案,第1章 HTML的基本标签-教案
  3. MYSQL多线程插入操作
  4. NLP中的词向量总结与实战:从one-hot到bert
  5. 题解 P1006 传纸条
  6. chm文件导入java_chm文件无法打开-解决方法
  7. 最新获得淘宝app商品详情原数据 的API
  8. Elasticsearch与最新的log4j2零日漏洞
  9. 10个开源电子商务平台
  10. 基于Android与多媒体的英文学习APP的设计
  11. OceanBase 业务数据库实践(二)── DB2 迁移
  12. 一键分享到新浪微博、腾讯微博、搜狐微博、人人网、开心网、百度收藏等js代码大全...
  13. OTTO机器人之APP蓝牙控制
  14. isArray 函数,转自 笨笨狗 blog
  15. Linux下双网卡分配同一网段地址问题分析
  16. 梅林 自动订阅_如何为4万名订阅者编写自动令牌空投脚本
  17. vue3 状态管理工具 pinia 使用
  18. Undeclared Identifier错误解决方法
  19. ocr文字识别如何识别文字?
  20. 意外的计算机音乐,富有灵魂的音乐ibass BF11意外发烧

热门文章

  1. android 获取wifi的ip地址吗,Android获取有线和无线(wifi)的IP地址
  2. ssh 远程登录_C.4 彻底解决-新版本Sentaurus TCAD的SSH远程登录问题!!!
  3. Python中的第三方模块(微信为例)
  4. 6-C/C++实现数据结构链表相关操作
  5. uban服务器系统,Web服务器-并发服务器-Epoll(3.4.5)
  6. mysql 建立一棵树_如何存储一颗树到文件或者数据库
  7. 1290 the mysql_ERROR 1290:The MySQL server is running with the --secure-file-priv option
  8. SAP License:凭证冲销
  9. SAP License:关于客户寄售的问题
  10. 如何将公式插入到word