这个C语言例子的例子是什么意思,他的可读性在哪里???

1、如果可以的话少用库函数便於不同的mcu和编译器间的移植

2、选择合适的算法和数据结构

应该熟悉算法语言,知道各种算法的优缺点具体资料请参见相应的参考资料,囿很多计算机书籍上都有介绍将比较慢的顺序查找法用较快的二分查找或乱序查找法代替,插入排序或冒泡排序法用快速排序、合并排序或根排序代替都可以大大提高程序执行的效率。.选择一种合适的数据结构也很重要比如你在一堆随机存放的数中使用了大量的插入囷删除指令,那使用链表要快得多数组与指针语句具有十分密码的关系,一般来说指针比较灵活简洁,而数组则比较直观容易理解。对于大部分的编译器使用指针比使用数组生成的代码更短,执行效率更高但是在Keil中则相反,使用数组比使用的指针生成的代码更短

3、使用尽量小的数据类型

能够使用字符型(char)定义的变量,就不要使用整型(int)变量来定义;能够使用整型变量定义的变量就不要用长整型(long int)能不使用浮点型(float)变量就不要使用浮点型变量。当然在定义变量后不要超过变量的作用范围,如果超过变量的范围赋值C编译器并不报错,但程序运行结果却错了而且这样的错误很难发现。在ICCAVR中可以在Options中设定使用printf参数,尽量使用基本型参数(%c、%d、%x、%X、%u和%s格式说明符)少用长整型参数(%ld、%lu、%lx和%lX格式说明符),至于浮点型的参数(%f)则尽量不要使用其它C编译器也一样。在其它条件不变的情况下使用%f参数,会使生成的代碼的数量增加很多执行速度降低。

4、使用自加、自减指令

通常使用自加、自减指令和复合赋值表达式(如a-=1及a+=1等)都能够生成高质量的程序代碼编译器通常都能够生成inc和dec之类的指令,而使用a=a+1或a=a-1之类的指令有很多C编译器都会生成二到三个字节的指令。在AVR单片适用的ICCAVR、GCCAVR、IAR等C编译器以上几种书写方式生成的代码是一样的也能够生成高质量的inc和dec之类的的代码。

可以使用运算量小但功能相同的表达式替换原来复杂的嘚表达式如下:

说明:位操作只需一个指令周期即可完成,而大部分的C编译器的“%”运算均是调用子程序来完成代码长、执行速度慢。通常只要求是求2n方的余数,均可使用位操作的方法来代替

1,防止一个头文件被重复包含

2重新定义一些类型,防止由于各种平台和編译器的不同而产生的类型字节数差异,方便移植

3,得到指定地址上的一个字节或字

6,得到一个结构体中field所占用的字节数

7按照LSB格式把兩个字节转化为一个Word

8,按照LSB格式把一个Word转化为两个字节

9得到一个变量的地址(word宽度)

10,得到一个字的高位和低位字节

11返回一个比X大的最接菦的8的倍数

12,将一个字母转换为大写

13判断字符是不是10进值的数字

14,判断字符是不是16进值的数字

15防止溢出的一个方法

16,返回数组元素的個数

18对于IO空间映射在存储空间的结构,输入输出处理

19,使用一些宏跟踪调试

A N S I标准说明了五个预定义的宏名它们是:

如果编译不是标准的,则可能仅支持以上宏名中的几个或根本不支持。记住编译程序也许还提供其它预定义的宏名

_ D AT E _宏指令含有形式为月/日/年的串,表示源攵件被翻译到代码时的日期

源代码翻译到目标代码的时间作为串包含在_ T I M E _中。串形式为时:分:秒

如果实现是标准的,则宏_ S T D C _含有十进制瑺量1如果它含有任何其它数,则实现是非标准的

可以定义宏,例如: 当定义了_DEBUG输出数据信息和所在文件所在行

20,宏定义防止使用时错誤用小括号包含

我们使用#把宏参数变为一个字符串,用##把两个宏参数贴合在一起.

二、当宏参数是另一个宏的时候

需要注意的是凡宏定义里囿用'#'或'##'的地方宏参数是不会再展开.

INT_MAX和A都不会再被展开, 然而解决这个问题的方法很简单. 加多一层中间转换宏. 加这层宏的用意是把所有宏的参數在这层里全部展开, 那么在转换宏里的那一个宏(_STR)就能得到正确的宏参数.

三、'#'和'##'的一些应用特例

即每次只能解开当前层的宏,所以__LINE__在第二层財能被解开;

我一直觉得指针是C语言例子最难嘚部分感觉学的特别差,今天想好好谈谈指针

指针在32位操作系统下是4个字节,在64位操作系统下是8个字节.

下面区别一下%p %x%p输出的是指针嘚格式,主要是16进制输出%x输出的是16进制,是int类型

  在64位操作系统下,%p输出的是8个字节%x输出的是4个字节,%p输出若不够8位会在前面补0.

冯諾依曼体系结构:  输入设备   cpu 内存(存储器)外存(硬盘) 输出设备。

指针是编程语言的一个对象利用地址,它的值指向存在电脑储存器Φ另一个地方的值由于利用地址能找到所需的变量单元,可以说指针指向该变量单元,在计算机的内存中内存中的每一个位置由一個独一无二的地址标识,内存中的每一个位置都包含一个值(这篇博客里面把指针指针变量讲的很清楚)

注意这些值的输出结果,下面區分一下指针和指针变量

指针是个变量,存放内存地址的单元int i =5;int* p=&i,&i就相当于指针,把i的指针&i赋值给了int*型指针变量pp中存放着&i,所以说指针變量就是存放指针的变量也可以说指针就是变量,用来存放地址的变量1k就是2^10次方个字节,1M就是2^10*2^10次方个字节,1G就是2^10*2^10*2^10次方个字节,所以在32位操莋系统上,有4G的空间用来编址,这也就很容易明白,在32位操作系统上指针为什么是4个字节,64位操作系统上是8个字节.

给指定的内存上写入数据*(int*)0x12ff7c=0x100;咗右值“=”右边的就是右值等号左边的就是左值。a作为右值的时候代表的是数组首元素的首地址&a[0]的意思,a不能作为左值但是a[i]可以作為左值。

一级指针在作为函数参数的时候调用的时候,函数的形参和实参分别占有不同的内存块,只是这个内存空间存放的指针指向嘚是同一块地址函数的形参只是实参的拷贝,在传值调用的时候对形参的修改不会影响实参。

但是一级指针在使用过程中应该改注意:

1.在传值调用的过程中不要在函数中改变形参的指向来达到改变实参指向的效果,他们占有不同的内存块修改形参不会影响实参。 2.在傳址调用的过程中形参和实参虽然占用不同的内存块但是内存空间存放的指针指向的是同一块地址,所以在形参中改变其指向空间的值如此实参指向的空间地址也发生改变。

从上面的运行结果可以看出在pointer1 函数中改变形参p的指向,并不会改变实参p的指向所以输入的值昰一堆脏数据。

但是进行如下的修改之后,看看运行的效果

修改之后的运行结果,从代码的改动可看出  pointer1函数中修改的不是形参指针的指向而是修改形参指针指向的空间的内容。这样就能达到一级指针做函数返回值的效果

二级指针的形式是**p,指向指针的指针通过二級指针,可以方便的通过改变形参的指向来达到改变实参的目的。

二级指针的使用一般不常见经常会用到typedef来使代码可读性更强,不然佷容易出错

数组指针就是能够指向数组的指针,int *p1[10]是一个指针数组 int (*p)[10]是数组指针,p先和*结合说明p是一个指针变量,然后指着指向的是一個大小为10个整型的数组所以p是一个指针,指向一个数组叫数组指针。

int arr[10],中arr和&arr虽然此处值一样但是代表的意义不一样,&arr代表的是数组的哋址arr以%p输出输出的是数组首元素的地址,&arr+1相当于跳过整个数组的大小所以&arr+1相对于&arr的差值为40.数组指针指向的是数组,存放的是数组的地址

编者按:C语言例子是开发嵌入式應用的主要工具然而C语言例子并非是专门为嵌入式系统设计,相当多的嵌入式系统较一般计算机系统对软件安全性有更苛刻的要求1998年,MISRA指出一些在C看来可以接受,却存在安全隐患的地方有127处之多2004年,MISRA对C的限制增加到141条

  嵌入式系统应用工程师借用计算机专家创建的C语言例子,使嵌入式系统应用得以飞速发展而MISRAC是嵌入式系统应用工程师对C语言例子嵌入式应用做出的贡献。如今MISRA C已经被越来越多的企业接受成为用于嵌入式系统的C语言例子标准,特别是对安全性要求极高的嵌入式系统软件应符合MISRA标准。

  从本期开始本刊将分6期,与读者共同学习MISRAC
  第一讲:“‘安全第一’的C语言例子编程规范”,简述MISRAC的概况
  第二讲:“跨越数据类型的重重陷阱”,介绍规范的数据定义和操作方式重点在隐式数据类型转换中的问题。
  第三讲:“指针、结构体、联合体的安全规范”解析如何安铨而高效地应用指针、结构体和联合体。
  第四讲:“防范表达式的失控”剖析MISRAC中关于表达式、函数声明和定义等的不良使用习惯,朂大限度地减小各类潜在错误
  第五讲:“准确的程序流控制”,表述C语言例子中控制表达式和程序流控制的规范做法
  第六讲:“构建安全的编译环境”,讲解与编译器相关的规范编写方式避免来自编译器的隐患。

C/C++语言无疑是当今嵌入式开发中最为常见的语言早期的嵌入式程序大都是用汇编语言开发的,但人们很快就意识到汇编语言所带来的问题——难移植、难复用、难维护和可读性极差佷多程序会因为当初开发人员的离开而必须重新编写,许多程序员甚至连他们自己几个月前写成的代码都看不懂C/C++语言恰恰可以解决这些問题。作为一种相对“低级”的高级语言C/C++语言能够让嵌入式程序员更自由地控制底层硬件,同时享受高级语言带来的便利对于C语言例孓和C++语言,很多的程序员会选择C语言例子而避开庞大复杂的C++语言。这是很容易理解的——C语言例子写成的代码量比C++语言的更小些执行效率也更高。

  对于程序员来说能工作的代码并不等于“好”的代码。“好”代码的指标很多包括易读、易维护、易移植和可靠等。其中可靠性对嵌入式系统非常重要,尤其是在那些对安全性要求很高的系统中如飞行器、汽车和工业控制中。这些系统的特点是:呮要工作稍有偏差就有可能造成重大损失或者人员伤亡。一个不容易出错的系统除了要有很好的硬件设计(如电磁兼容性),还要有佷健壮或者说“安全”的程序

  然而,很少有程序员知道什么样的程序是安全的程序很多程序只是表面上可以干活,还存在着大量嘚隐患当然,这其中也有C语言例子自身的原因因为C语言例子是一门难以掌握的语言,其灵活的编程方式和语法规则对于一个新手来说佷可能会成为机关重重的陷阱同时,C语言例子的定义还并不完全即使是国际通用的C语言例子标准,也还存在着很多未完全定义的地方要求所有的嵌入式程序员都成为C语言例子专家,避开所有可能带来危险的编程方式是不现实的。最好的方法是有一个针对安全性的C语訁例子编程规范告诉程序员该如何做。

Association以下简称MISRA)的组织。它是致力于协助汽车厂商开发安全可靠的软件的跨国协会其成员包括:AB汽车电子、罗孚汽车、宾利汽车、福特汽车、捷豹汽车、路虎公司、Lotus公司、MIRA公司、Ricardo公司、TRW汽车电子、利兹大学和福特VISTEON汽车系统公司。

Standardization,简称ISO)的“标准C语言例子”经历了从C90、C96到C99的变动但是,嵌入式程序员很难将ISO标准当作编写安全代码的规范一是因为标准C语言例子并不是针對代码安全的,也并不是专门为嵌入式应用设计的;二是因为“标准C语言例子”太庞大了很难操作。MISRAC:1998规范的产生恰恰弥补了这方面的空皛

  随着很多汽车厂商开始接受MISRAC编程规范,MISRAC:1998也成为汽车工业中最为著名的有关安全性的C语言例子规范2004年,MISRA出版了该规范的新版本——MISRAC:2004在新版本中,还将面向的对象由汽车工业扩大到所有的高安全性要求(Critical)系统在MISRAC:2004中,共有强制规则121条推荐规则20条,并删除了15条旧規则任何符合MISRAC:2004编程规范的代码都应该严格的遵循121条强制规则的要求,并应该在条件允许的情况下尽可能符合20条推荐规则

  MISRAC:2004将其141条规則分为21个类别,每一条规则对应一条编程准则详细情况如表1所列。

  最初MISRAC:1998编程规范的建立是为了增强汽车工业软件的安全性。可能慥成汽车事故的原因有很多如图1所示,设计和制造时埋下的隐患约占总数的15%其中也包括软件的设计和制造。MISRAC:1998就是为了减小这部分隐患洏制定的

  MISRAC编程规范的推出迎合了很多汽车厂商的需要,因为一旦厂商在程序设计上出现了问题用来补救的费用将相当可观。1999年7月22ㄖ通用汽车公司(General Motors)就曾经因为其软件设计上的一个问题,被迫召回350万辆已经出厂的汽车损失之大可想而知。

注:以下信息来源于成嘟信息工程学院

对于程序员来说能工作的代码并不等于“好”的代码。“好”代码的指标很多包括易读、易维护、易移植和可靠等。其中可靠性对嵌入式系统非常重要,尤其是在那些对安全性要求很高的系统中如飞行器、汽车和工业控制中。这些系统的特点是:只偠工作稍有偏差就有可能造成重大损失或者人员伤亡。一个不容易出错的系统除了要有很好的硬件设计(如电磁兼容性),还要有很健壮戓者说“安全”的程序

然而,很少有程序员知道什么样的程序是安全的程序很多程序只是表面上可以干活,还存在着大量的隐患当嘫,这其中也有C语言例子自身的原因因为C语言例子是一门难以掌握的语言,其灵活的编程方式和语法规则对于一个新手来说很可能会成為机关重重的陷阱同时,C语言例子的定义还并不完全即使是国际通用的C语言例子标准,也还存在着很多未完全定义的地方要求所有嘚嵌入式程序员都成为C语言例子专家,避开所有可能带来危险的编程方式是不现实的。最好的方法是有一个针对安全性的C语言例子编程規范告诉程序员该如何做。

本规范在制定过程中主要参考了业界比较推崇的《华为软件编程规范和范例》和《MISRA 2004规则》,适合于非计算機专业的C语言例子初学者使用目的在于在教学中培养学生良好的编程规范和意识、素质,促进所设计程序安全、健壮、可靠、可读与可維护(程序简单、清晰)考虑到面向的是初学者,为便于教学和课程考核操作本规范中的要求比较基本。事实上很多公司都有自己规定嘚代码风格,包括命名规则、缩进规则等学生参加工作后,应再进一步学习和应用公司的规范

建议学生在学习本规范的同时,花点时間阅读本规范的参考文献原文特别是熟读本规范的参考文献之一的《“安全第一”的C语言例子编程规范》,深刻理解编程规范与程序安铨、健壮、可靠、可读、可维护间的关系和作用在学习和工作中养成良好的编程风格。



7-15:尽量用乘法或其它方法代替除法特别是浮点運算中的除法。

7-16:不要一味追求紧凑的代码
说明:因为紧凑的代码并不代表高效的机器码。8-1:在软件设计过程中构筑软件质量

8-2:代码質量保证优先原则
(1)正确性,指程序要实现设计要求的功能
(2)稳定性、安全性,指程序稳定、可靠、安全
(3)可测试性,指程序偠具有良好的可测试性
(4)规范/可读性,指程序书写风格、命名规则等要符合规范
(5)全局效率,指软件系统的整体效率
(6)局部效率,指某个模块/子模块/函数的本身效率
(7)个人表达方式/个人方便性,指个人编程习惯

8-3:只引用属于自己的存贮空间。

说明:若模塊封装的较好那么一般不会发生非法引用他人的空间。

8-4:防止引用已经释放的内存空间

说明:在实际编程过程中,稍不留心就会出现茬一个模块中释放了某个内存块(如C 语言指针)而另一模块在随后的某个时刻又使用了它。要防止这种情况发生

8-5:过程/函数中分配的內存,在过程/函数退出之前要释放

8-6:过程/函数中申请的(为打开文件而使用的)文件句柄,在过程/函数退出之前要关闭

说明:分配的內存不释放以及文件句柄不关闭,是较常见的错误而且稍不注意就有可能发生。这类错误往往会引起很严重后果且难以定位。

8-7:防止內存操作越界

说明:内存操作主要是指对数组、指针、内存地址等的操作。内存操作越界是软件系统主要错误之一后果往往非常严重,所以当我们进行这些操作时一定要仔细小心

8-8:认真处理程序所能遇到的各种出错情况。

8-9:系统运行之初要初始化有关变量及运行环境,防止未经初始化的变量被引用

8-10:系统运行之初,要对加载到系统中的数据进行一致性检查

说明:使用不一致的数据,容易使系统進入混乱状态和不可知状态

8-11:严禁随意更改其它模块或系统的有关设置和配置。

说明:编程时不能随心所欲地更改不属于自己模块的囿关设置如常量、数组的大小等。

8-12:不能随意改变与其它模块的接口

8-13:充分了解系统的接口之后,再使用系统提供的功能

示例:在B 型機的各模块与操作系统的接口函数中,有一个要由各模块负责编写的初始化过程此过程在软件系统加载完成后,由操作系统发送的初始囮消息来调度因此就涉及到初始化消息的类型与消息发送的顺序问题,特别是消息顺序若没搞清楚就开始编程,很容易引起严重后果以下示例引自B 型曾出现过的实际代码,其中使用了FID_FETCH_DATA与FID_INITIAL 初始化消息类型注意B

中(**)之前;要么就必须考虑(**)处的判断语句是否可以用(不使用alarm_module_list 变量的)其它方式替代,或者是否可以取消此判断语句

8-14:编程时,要防止差1 错误

说明:此类错误一般是由于把“<=”误写成“<”或“>=”误写成“>”等造成的,由此引起的后果很多情况下是很严重的,所以编程时一定要在这些地方小心。当编完程序后应对这些操作符进行彻底检查。

8-15:要时刻注意易混淆的操作符当编完程序后,应从头至尾检查一遍这些操作符以防止拼写错误。

说明:形式楿近的操作符最容易引起误用如C/C++中的“=”与“==”、“|”与“||”、“&”与“&&”等,若拼写错了编译器不一定能够检查出来。

8-16:有可能的話if 语句尽量加上else 分支,对没有else 分支的语句要小心对待;switch语句必须有default 分支

8-17:Unix 下,多线程的中的子线程退出必需采用主动退出方式即子線程应return 出口。

说明:goto 语句会破坏程序的结构性所以除非确实需要,最好不使用goto 语句

8-19:精心地构造、划分子模块,并按“接口”部分及“内核”部分合理地组织子模块以提高“内核”部分的可移植性和可重用性。

说明:对不同产品中的某个功能相同的模块若能做到其內核部分完全或基本一致,那么无论对产品的测试、维护还是对以后产品的升级都会有很大帮助。

8-20:精心构造算法并对其性能、效率進行测试。

8-21:对较关键的算法最好使用其它算法来确认

8-22:时刻注意表达式是否会上溢、下溢。

8-23:使用变量时要注意其边界值的情况

8-24:留心程序机器码大小(如指令空间大小、数据空间大小、堆栈空间大小等)是否超出系统有关限制。

8-25:为用户提供良好的接口界面使用戶能较充分地了解系统内部运行状态及有关系统出错情况。

8-26:系统应具有一定的容错能力对一些错误事件(如用户误操作等)能进行自動补救。

8-27:对一些具有危险性的操作代码(如写硬盘、删数据等)要仔细考虑防止对数据、硬件等的安全构成危害,以提高系统的安全性

8-28:使用第三方提供的软件开发工具包或控件时,要注意以下几点:
(1)充分了解应用接口、使用环境及使用时注意事项
(2)不能过汾相信其正确性。
(3)除非必要不要使用不熟悉的第三方工具包与控件。
说明:使用工具包与控件可加快程序开发速度,节省时间泹使用之前一定对它有较充分的了解,同时第三方工具包与控件也有可能存在问题

8-29:资源文件(多语言版本支持),如果资源是对语言敏感的应让该资源与源代码文件脱离,具体方法有下面几种:使用单独的资源文件、DLL 文件或其它单独的描述文件(如数据库格式)9-1:打開编译器的所有告警开关对程序进行编译

9-2:在产品软件(项目组)中,要统一编译开关选项

9-3:通过代码走读及审查方式对代码进行检查。

说明:代码走读主要是对程序的编程风格如注释、命名等以及编程时易出错的内容进行检查可由开发人员自己或开发人员交叉的方式进行;代码审查主要是对程序实现的功能及程序的稳定性、安全性、可靠性等进行检查及评审,可通过自审、交叉审核或指定部门抽查等方式进行

9-4:测试部测试产品之前,应对代码进行抽查及评审

9-5:编写代码时要注意随时保存,并定期备份防止由于断电、硬盘损坏等原因造成代码丢失。

9-6:同产品软件(项目组)内最好使用相同的编辑器,并使用相同的设置选项

说明:同一项目组最好采用相同的智能语言编辑器,如Muiti EditorVisual Editor 等,并设计、使用一套缩进宏及注释宏等将缩进等问题交由编辑器处理。

9-7:合理地设计软件系统目录方便开发囚员使用。

说明:方便、合理的软件系统目录可提高工作效率。目录构造的原则是方便有关源程序的存储、查询、编译、链接等工作哃时目录中还应具有工作目录----所有的编译、链接等工作应在此目录中进行,工具目录----有关文件编辑器、文件查找等工具可存放在此目录中

9-8:某些语句经编译后产生告警,但如果你认为它是正确的那么应通过某种手段去掉告警信息。

9-9:使用代码检查工具(如C 语言用PC-Lint)对源程序检查

9-10:使用软件工具(如 LogiSCOPE)进行代码审查。

10-1:单元测试要求至少达到语句覆盖

10-2:单元测试开始要跟踪每一条语句,并观察数据流及變量的变化

10-3:清理、整理或优化后的代码要经过审查及测试。

10-4:代码版本升级要经过严格测试

10-5:使用工具软件对代码版本进行维护。

10-6:正式版本上软件的任何修改都应有详细的文档记录

10-7:发现错误立即修改,并且要记录下来

10-8:关键的代码在汇编级跟踪。

10-9:仔细设计並分析测试用例使测试用例覆盖尽可能多的情况,以提高测试用例的效率

10-11:尽可能模拟出程序的各种出错情况,对出错处理代码进行充分的测试

10-12:仔细测试代码处理数据、变量的边界情况。

10-13:保留测试信息以便分析、总结经验及进行更充分的测试。

10-14:不应通过“试”来解决问题应寻找问题的根本原因。

10-15:对自动消失的错误进行分析搞清楚错误是如何消失的。

10-16:修改错误不仅要治表更要治本。

10-17:测试时应设法使很少发生的事件经常发生

10-18:明确模块或函数处理哪些事件,并使它们经常发生

10-19: 坚持在编码阶段就对代码进行彻底嘚单元测试,不要等以后的测试工作来发现问题

10-20:去除代码运行的随机性(如去掉无用的数据、代码及尽可能防止并注意函数中的“内蔀寄存器”等),让函数运行的结果可预测并使出现的错误可再现。11-1:用宏定义表达式时要使用完备的括号。

11-2:将宏所定义的多条表达式放在大括号中

11-3:使用宏时,不允许参数发生变化

在变量名中使用下划线是一种风格。使用或完全不使用下划线都没有错误重要的是偠保持一致性——在整个程序中使用相同的命名规则。这就是说如果你在一个小组环境中编程,你和其它小组成员应该制定一种命名规則并自始至终使用这种规则。如果有人使用了别的命名规则那么集成的程序读起来将是很费劲的。此外你还要与程序中用到的第三方库(如果有的话)所使用的风格保持一致。如果可能的话你应该尽量使用与第三方库相同的命名规则,这将加强你的程序的可读性和一致性

在编写程序时,你不必拘泥于一种特定的命名法——你完全可以建立自己的派生命名法特别是在为自己的typedef命名时。例如有一个名為SOURCEFILE的typedef,用来保存源文件名、句柄、行号、最后编译日期和时间、错误号等信息你可以引入一个类似“sf”(sourcefile)的前缀符号,这样当你看到一個名为sfBuffer的变量时,你就会知道该变量保存了SOURCEFILE结构中的部分内容

不管怎样,在命名变量或函数时引入某种形式的命名规则是一个好主意,尤其是当你与其它程序员共同开发一个大的项目时或者在Microsoft Windows这样的环境下工作时。采用一种认真设计好的命名规则将有助于增强你的程序的可读性尤其是当你的程序非常复杂时。

使用注释会影响程序的速度、大小或效率吗?

不会当你的程序被编译时,所有的注释都会被忽略掉只有可执行的语句才会被分析,并且被放入最终编译所得的程序版本中

因为注释并不会给程序的速度、大小或效率带来负担,所以你应该尽量多使用注释你应该在每一个程序模块的头部都加上一段注释,以解释该模块的作用和有关的特殊事项同样,你也要为烸一个函数加上注释其中应包括作者姓名、编写日期、修改日期和原因、参数使用指导、函数描述等信息。这些信息将帮助其它程序员哽好地理解你的程序也有助于你以后回忆起一些关键的实现思想。

在源代码中也应该使用注释(在语句之间)例如,如果有一部分代码比較复杂或者你觉得有些地方要进一步说明,你就应该毫不犹豫地在这些代码中加入注释这样做可能会花费一点时间,但这将为你或其咜人节省几个小时的宝贵时间因为只需看一下注释,人们就能马上知道你的意图

在19.4中有一个例子,它表明了使用注释、空白符和下劃线命名规则是如伺使程序更清晰、更易懂的

使用空白符会影响程序的速度、大小或效率吗?

不会。与注释一样所有的空白符都会被编譯程序忽略掉。当你的程序被编译时所有的空白符都会忽略掉,只有可执行的语句才会被分析并且被放入最终编译所得的程序版本中。

骆驼式命令法正如它的名称所表示的那样,是指混合使用大小写字母来构成变量和函数的名字例如,下面是分别用骆驼式命名法和丅划线法命名的同一个函数:
第一个函数名使用了骆驼式命名法——函数名中的每一个逻辑断点都有一个大写字母来标记;第二个函数名使用了下划线法----函数名中的每一个逻辑断点都有一个下划线来标记

骆驼式命名法近年来越来越流行了,在许多新的函数库和Microsoft Windows这样的环境Φ它使用得当相多。另一方面下划线法是c出现后开始流行起来的,在许多旧的程序和UNIX这样的环境中它的使用非常普遍。

不会当你嘚程序被编译时,每一个变量名和函数名都会被转换为一个“符号”——对原变量或原函数的一种较短的符号性的表示因此,无论你使鼡下面的哪一个函数名结果都是一样的:
一般说来,你应该使用描述性的函数名和变量名这样可以加强程序的可读性。你可以查阅编譯程序文档看一下允许有多少个有效字符,大多数ANSI编译程序允许有至少31个有效字符也就是说,只有变量名或函数名的前31个字符的唯一性会被检查其余的字符将被忽略掉。

一种较好的经验是使函数名或变量名读起来符合英语习惯就好象你在读一本书一样——人们应该能读懂你的函数名或变量名,并且能很容易地识别它们并知道它们的大概作用

在C中,使用大括号的方法无所谓对还是错——只要每个开括号后都有一个闭括号你的程序中就不再会出现与大括号有关的问题。然而有三种著名的大括号格式经常被使用:

注意,在Kb&R格式中開括号总是与使用它的语句在同一行上,而闭括号总是在它所关闭的语句的下一行上并且与该语句对齐。例如在上例中,if语句的开括號和它在同一行上|f语句的闭括号在它的下一行上,并且与它对齐在与if语句对应的else条件语句以及出现在程序段后部的while语句中,情况也是這样的

不管你使用哪一种格式,一定要保持前后一致——这将有助于你自己或其它人更方便地读你的程序 

一般说来,变量名或函数名應该足够长以有效地描述所命名的变量或函数。应该避免使用短而模糊的名字因为它们在别人理解你的程序时会带来麻烦。例如不偠使用象这样的短而模糊的函数名:
而应该使用更长一些的函数名,象下面这样:
这对变量名也是同样适用的例如,与其使用这样一个短而模糊的变量名:
不如将其扩展为完整的描述:
使用扩展了的名字会使程序更易读更易理解。大多数ANSI编译程序允许有至少31个有效字符——即只有变量或函数名的前31个字符的唯一性会被检查一种较好的经验是使函数名或变量名读起来符合英语习惯,就好象你在读一本书┅样一人们应该能读懂你的函数名或变量名并且能很容易地识别它们并知道它们的大概作用。

匈牙利命名法是由Microsoft公司的程序员Charles Simonyi(无疑是个匈牙利人的后裔)提出的在这种命名法中,变量名或函数名要加上一个或两个字符的前缀用来表示变量或函数的数据类型。

这种命名法囿许多好处它被广泛应用于象Microsoft Windows这样的环境中。关于匈牙利命名法的详细解释以及其中的一些命名标准

在C语言例子中,一个调用自身(不管是直接地还是间接地)的函数被称为是递归的(recursive)你可能不明白究竟为什么一个函数要调用自身,要解释这种情况最好先举一个例子。一個经典的马上可以举出来的例子就是计算整数的阶乘为了计算一个整数的阶乘值,你要用这个数(x)乘以它的前一个数(X一1)并且一直乘下去,直到到达1例如,5的阶乘可以这样来计算:
如果X是5你可以把这个算式转换为一个等式:

递归是一个简洁的概念,同时也是一种很有用嘚手段但是,使用递归是要付出代价的与直接的语句(如while循环)相比,递归函数会耗费更多的运行时间并且要占用大量的栈空间。递归函数每次调用自身时都需要把它的状态存到栈中,以便在它调用完自身后程序可以返回到它原来的状态。未经精心设计的递归函数总昰会带来麻烦

哪种方法最好呢?这个问题没有一个唯一的答案。如果你在编写一个Windows程序那么TRUE和FALSE都是已经为定义好的,你没有必要再建立洎己的定义在其它情况下,你可以从前文所介绍的几种方法中选择一种

空循环并不会无休止地进行下去——在重复预先指定的次数后,它就会退出循环无穷循环会无休止地进行下去,并且永远不会退出循环把空循环和无穷循环对比一下,就能很好地说明它们之间的區别

下面是一个空循环的例子:
注意,在上例中在for循环的闭括号后直接加入了一个分号。正如你可能已经知道的那样C语言例子并不偠求在for循环后加分号,通常只有包含在for循环中的语句后面才会带分号

在for循环后面直接加入分号(并且不使用大括号),即可建立一个空循环——实际上是一个不包含任何语句的循环在上例中,当for循环执行时变量x将自增500,000次而在每一次自增运算期间,没有进行任何处理

那么,空循环有什么用呢?在大多数情况下它的作用就是在程序中设置一次暂停。前面的例子将使程序“暂停”一段时间即计算机数到500,000所需的时间然而,空循环还有更多的用处请看下例:
这个例子用一个空循环来等待一次击键操作。当程序需要显示类似"Press Any Key ToContinue"这样的信息時这种方法是很有用的(假设你的用户很聪明,不会执着地在键盘上寻找"Any Key"!)

无穷循环与空循环不同,它永远不会结束下面是一个无穷循環的例子:
在这个例子中,while语句中包含了一个非零常量因此,while的条件永远为真循环永远不会结束。注意在闭括号后面直接加入一个汾号,因此while语句中不包含任何其它语句循环将无法终止(除非终止程序)。

9 代码编辑、编译、审查

我要回帖

更多关于 C语言例子 的文章

 

随机推荐