C 程序设计最佳实践

文章作者 100test 发表时间 2007:09:11 12:49:28
来源 100Test.Com百考试题网


  随着计算机语言的发展,我们现在编写一个程序越来越容易了。利用一些软件开发工具,往往只要通过鼠标的拖拖点点,计算机就会自动帮你生成许多代码。但在很多时候,计算机的这种能力被滥用了,我们往往只考虑把这个程序搭起来,而不去考虑程序的性能如何,程序是否足够的健壮。而此节课的目的主要是介绍一些编码的经验,让大家编写的程序更加健壮和高性能。

  1、Prefer const and inline to #define

  在C 编程中应该尽量使用const和inline来代替#define,尽量做到能不用#define就不用。#define常见的用途有“定义常量”以及“定义宏”,但其中存在诸多的弊病。

  第一,查错不直观,不利于调试。Define的定义是由预处理程序处理的,作的是完全的文本替换,不做任何的类型检查。在编译器处理阶段,define定义的东西已经被完全替换了,这样在debug的时候就看不到任何的相关信息,即跟踪时不能step into宏。例如,把ASPECT_RATIO用define定义成1.653,编译器就看不到ASPECT_RATIO这个名字了。如果编译器报1.653错,那么就无从知道此1.653来自于何处。在真正编码的时候应该使用如下的语句来定义:


static const double ASPECT_RATIO = 1.653.

  第二,没有任何类型信息,不是type safe。因为它是文本级别的替换,这样不利于程序的维护。

  第三,define的使用很容易造成污染。比如,如果有两个头文件都定义了ASPECT_RATIO, 而一个CPP文件又同时包含了这两个头文件,那么就会造成冲突。更难查的是另外一种错误,比如有如下的代码:
  // in header file def.h
  #define Apple 1
  #define Orange 2
    #define Pineapple 3
   …
  // in some cpp file that includes the def.h
  enum Colors {White, Black, Purple, Orange}.

  在.h文件中Orange被定义成水果的一种,而在.cpp文件中Orange又成为了一种颜色,那么编译器就会把此处的Orange替换成2,编译可能仍然可以通过,程序也能够运行,但是这就成了一个bug,表现出古怪的错误,且很难查错。再比如定义了一个求a与b哪个数大的宏,#define max(a,b) ((a) > (b) ? (a) : (b))
  int a = 5, b = 0.
  max( a, b).
  max( a, b 10).

  在上面的操作中,max( a, b). 语句中a被 了两次,而max( a, b 10). 语句中a只加了一次,这样在程序处理中就很有可能成为一个bug,且此bug也非常的难找。在实际编码时可以使用如下的语句来做:
  template
  inline const T&.
  max(const T&. a, const T&. b) { return a > b ? a : b. }

  2、Prefer C -style casts

  在程序中经常会需要把一种类型转换成另外一种类型,在C 中应该使用static_cast、const_cast、dynamic_cast、reinterpret_cast关键字来做类型转换。因为这有以下好处,一是其本身就是一种注释,在代码中看到上面这些关键字就可马上知道此处是进行类型转换。二是C语言中类型转换通常是很难进行搜索的,而通过关键字cast则可以很容易的找到程序中出现类型转换的地方了。

  3、Distinguish between prefix and postfix forms of increment and decrement operators

  通常对于操作系统或编译器自身支持的类型,prefix(前缀,如 i)与postfix(后缀,如i )的效果是一样的。因为现在的编译器都很聪明,它会自动做优化,这两者的汇编代码是一样的,性能不会有差别。但有时候也会有不同的,如一些重载了操作符的类型。下面是模拟prefix与postfix的操作过程,可以发现在postfix操作中会生成一个临时变量,而这一临时变量是会占用额外的时间和开销的。
  // prefix form: increment and fetch
  UPInt&. UPInt::operator ()
   {
    *this = 1. // increment
   return *this. // fetch
   }
  // postfix form: fetch and increment
   const UPInt UPInt::operator (int)
   {
    UPInt oldValue = *this. // fetch
    (*this). // increment
    return oldValue. // return what was fetched
   }

  一般情况下不需要区分是先 ,还是后 ,但是我们在编写程序的时候最好能习惯性的将其写成 i的形式,如在使用STL中的iterator时,prefix与postfix会有相当大的性能差异。请不要小看这些细节,实际在编写程序的时候,若不注意具体细节,你会发现程序的性能会非常的低。但要注意,虽然在大多数情况下可以用prefix来代替postfix,但有一种情况例外,那就是有[]操作符时,比如gzArray [ index] 是不等于 gzArray[index ]的。


相关文章


二级C语言教程章节测试7.函数
计算机等级考试经典推荐:怎样学习C语言
计算机等级考试二级C语言考后心得
提高Java代码可重用性的三个措施
C 程序设计最佳实践
C 中使用union的几点思考
初学者必知:VB10个小编程
送给正在学习C 朋友的50条建议
C语言高效编程的四大绝招
澳大利亚华人论坛
考好网
日本华人论坛
华人移民留学论坛
英国华人论坛