C语言编程要点第19章编程风格和标准.docx
《C语言编程要点第19章编程风格和标准.docx》由会员分享,可在线阅读,更多相关《C语言编程要点第19章编程风格和标准.docx(16页珍藏版)》请在冰豆网上搜索。
C语言编程要点第19章编程风格和标准
C语言编程要点---第19章 编程风格和标准
第19章 编程风格和标准
本章集中讨论程序的布局,包括注释和空白符的使用,变量和函数的命名标准,使用大括号的技巧等内容。
在本章中,你将会了解到:
使用注释和空白符不会影响程序的速度、大小和效率;在代码中加大括号的三种格式;有关变量和函数命名的两种命名法(骆驼式和匈牙利式);在变量名和函数名中加下划线可增加其可读性;怎样为函数命名以及函数名和变量名应该有多长。
除了有关命名的约定和标准外,本章还将讨论这样一些常见的编程问题:
递归(它是什么以及如何使用它);空循环;无穷循环;通过while,do...while和for循环进行重复处理;continue语句和break语句的区别;在程序中表示真和假的最好办法。
本章涉及的内容很多,你要耐心学习,并且一定要认真学习命名的格式和约定,这些内容有助于加强你的程序的可读性。
19.1. 应该在变量名中使用下划线吗?
在变量名中使用下划线是一种风格。
使用或完全不使用下划线都没有错误,重要的是要保持一致性——在整个程序中使用相同的命名规则。
这就是说,如果你在一个小组环境中编程,你和其它小组成员应该制定一种命名规则。
并自始至终使用这种规则。
如果有人使用了别的命名规则,那么集成的程序读起来将是很费劲的。
此外,你还要与程序中用到的第三方库(如果有的话)所使用的风格保持一致。
如果可能的话,你应该尽量使用与第三方库相同的命名规则,这将加强你的程序的可读性和一致性。
许多C程序员发现在命名变量时使用下划线是很方便的,这可能是因为加下划线会大大加强可读性。
例如,下面的两个函数名是相似的,但使用下划线的函数名的可读性更强:
checkdiskspaceavailable(selecteddiskdrive);
CheckDiskSpaceAvailable(SelectedDiskDrive);
上例中的第二个函数名使用了骆驼式命名法——见19.5中关于骆驼式的解释。
请参见:
19.2可以用变量名来指示变量的数据类型吗?
19.5什么是骆驼式命名法?
19.6较长的变量名会影响程序的速度、大小或效率吗?
19.9一个变量名应该使用多少个字母?
ANSI标准允许有多少个有效字符?
19.10什么是匈牙利式命名法?
应该使用它吗?
19.2. 可以用变量名来指示变量的数据类型吗?
可以。
在变量名中指出数据类型已经成为今天的大型复杂系统中普遍使用的一条规则。
通常,变量类型由一个或两个字符表示,并且这些字符将作为变量名的前缀。
使用这一技术的一种广为人知的命名规则就是匈牙利命名法,它的名称来自于Microsoft公司的程序员CharlesSimonyi。
表19.2列出了一些常用的前缀。
表19.2一些常用的匈牙利命名法前缀
---------------------------------------------------------------------------------
数据类型 前缀 例子
---------------------------------------------------------------------------------
char c clnChar
int i iReturnValue
long l lNumRecs
string sz szlnputString(以零字节结束)
int array ai aiErrorNumbers
char* psz pszInputString
---------------------------------------------------------------------------------
象MicrosoftWindows这样的环境,就大量使用了匈牙利命名法或其派生体。
其它一些第四代环境,例如VisualBasic和Access,也采用了匈牙利命名法的一种变体。
在编写程序时,你不必拘泥于一种特定的命名法——你完全可以建立自己的派生命名法,特别是在为自己的typedef命名时。
例如,有一个名为SOURCEFILE的typedef,用来保存源文件名、句柄、行号、最后编译日期和时间、错误号等信息。
你可以引入一个类似“sf”(sourcefile)的前缀符号,这样,当你看到一个名为sfBuffer的变量时,你就会知道该变量保存了SOURCEFILE结构中的部分内容。
不管怎样,在命名变量或函数时,引入某种形式的命名规则是一个好主意,尤其是当你与其它程序员共同开发一个大的项目时,或者在MicrosoftWindows这样的环境下工作时。
采用一种认真设计好的命名规则将有助于增强你的程序的可读性,尤其是当你的程序非常复杂时。
请参见:
19.1应该在变量名中使用下划线吗?
19.5什么是骆驼式命名法?
19.6较长的变量名会影响程序的速度、大小或效率吗?
19.9一个变量名应该使用多少个字母?
ANSI标准允许有多少个有效字符?
19.10什么是匈牙利式命名法?
应该使用它吗?
19.3. 使用注释会影响程序的速度、大小或效率吗?
不会。
当你的程序被编译时,所有的注释都会被忽略掉,只有可执行的语句才会被分析,并且被放入最终编译所得的程序版本中。
因为注释并不会给程序的速度、大小或效率带来负担,所以你应该尽量多使用注释。
你应该在每一个程序模块的头部都加上一段注释,以解释该模块的作用和有关的特殊事项。
同样,你也要为每一个函数加上注释,其中应包括作者姓名、编写日期、修改日期和原因、参数使用指导、函数描述等信息。
这些信息将帮助其它程序员更好地理解你的程序,也有助于你以后回忆起一些关键的实现思想。
在源代码中也应该使用注释(在语句之间)。
例如,如果有一部分代码比较复杂,或者你觉得有些地方要进一步说明,你就应该毫不犹豫地在这些代码中加入注释。
这样做可能会花费一点时间,但这将为你或其它人节省几个小时的宝贵时间,因为只需看一下注释,人们就能马上知道你的意图。
在19.4中有一个例子,它表明了使用注释、空白符和下划线命名规则是如伺使程序更清晰、更易懂的。
请参见:
19.4使用空白符会影响程序的速度、大小或效率吗?
19.6较长的变量名会影响程序的速度、大小或效率吗?
19.4. 使用空白符会影响程序的速度、大小或效率吗?
不会。
与注释一样,所有的空白符都会被编译程序忽略掉。
当你的程序被编译时,所有的空白符都会忽略掉,只有可执行的语句才会被分析,并且被放入最终编译所得的程序版本中。
在C程序中用空白符隔开可执行语句、函数和注释等,将有助于提高程序的可读性和清晰度。
许多时候,只要在语句之间加入空行,就可提高程序的可读性。
请看下面的这段代码:
/*clcpybyGBlansten*/
voidclcpy(EMP*e,intrh,intot)
{e->grspy=(e->rt*rh)+(e->rt*ot*1.5);
e->txamt=e->grspy*e->txrt;
e->ntpy=e->grspy-e->txamt;
updacctdata(e);
if(e->dd==false)cutpyck(e);
elseprtstb(e);}
你可以看到,这个函数确实是一团糟。
尽管这个函数显然是正确的,但恐怕这个世界上没有一个程序员愿意去维护这样的代码。
如果采用本章中的一些命名规则(例如使用下划线,少用一些短而模糊的名字),使用一些大括号技巧,加入一些空白符和注释,那么这个函数将会是下面这个样子:
/********************************************************************************/
FunctionName:
calc_pay
Parameters:
emp -EMPLOYEEpointerthatpointstoemployeedata
reg-hours -Thenumberofregularhours(<=40)employee
hasworked
ot-hours -Thenumberofovertimehours(>40)employee
hasworked
Author:
GernBlansten
DateWritten:
13dec1993
Modification:
04sep1994byLloydE.Work
-Rewrotefunctiontomakeitreadablebyhumanbeings.
Description:
Thisfunctioncalculatesanemployee'sgrossbay,tax
amount,andnetpay,andeitherprintsapaycheckforthe
employeeor(inthecaseofthosewhohavedirectdeposit)
printsapaycheckstub.
/*********************************************************************************/
voidcalc_pay(EMPLOYEE*emp,intreghours,intor_hours)
{
/*gross_pay=(employeerate*regularhours)+
(employeerate*overtimehours*1.5)*/
emp->gross_pay=(emp->rate*reg_hours)+
(emp->rate*othours*1.5);
/*taxamount=gross_pay*employee'staxrate*/
emp->taxamount=emp->gross_pay*emp->tax-rate;
/*netpay=grosspay-taxamount*/
emp->net-pay=emp->grosspay-emp->tax_amount;
/*updatetheaccountingdata*/
updateaccountingdata(emp);
/*checkfordirectdeposit*/
if(emp->direct_deposit==false)
cut_paycheck(emp); /*printapaycheck*/
else
print_paystub(emp); /*printapaycheckstub*/
}
你可以看到,Lloyd版本(该版本中使用了大量的注释、空行、描述性变量名等)的可读性比糟糕的Gern版本要强得多。
你应该尽量在你认为合适的地方使用空白符(和注释符等),这将大大提高程序的可读性一一当然,这可能会延长你的工作时间。
请参见:
19.3使用注释会影响程序的速度、大小或效率吗?
19.6较长的变量名会影响程序的速度、大小或效率吗?
19.5. 什么是骆驼式命名法?
骆驼式命令法,正如它的名称所表示的那样,是指混合使用大小写字母来构成变量和函数的名字。
例如,下面是分别用骆驼式命名法和下划线法命名的同一个函数:
PrintEmployeePaychecks();
printemployeepaychecks();
第一个函数名使用了骆驼式命名法——函数名中的每一个逻辑断点都有一个大写字母来标记;第二个函数名使用了下划线法----函数名中的每一个逻辑断点都有一个下划线来标记。
骆驼式命名法近年来越来越流行了,在许多新的函数库和MicrosoftWindows这样的环境中,它使用得当相多。
另一方面,下划线法是c出现后开始流行起来的,在许多旧的程序和UNIX这样的环境中,它的使用非常普遍。
请参见:
19.1应该在变量名中使用下划线吗?
19.2可以用变量名来指示变量的数据类型吗?
19.6较长的变量名会影响程序的速度、大小或效率吗?
19.9一个变量名应该使用多少个字母?
ANSI标准允许有多少个有效字符?
19.10什么是匈牙利式命名法?
应该使用它吗?
19.6. 较长的变量名会影响程序的速度、大小或效率吗?
不会,当你的程序被编译时,每一个变量名和函数名都会被转换为一个“符号”——对原变量或原函数的一种较短的符号性的表示。
因此,无论你使用下面的哪一个函数名,结果都是一样的:
PrintOutAllTheClientsMonthEndReports();
prt_rpts();
一般说来,你应该使用描述性的函数名和变量名,这样可以加强程序的可读性。
你可以查阅编译程序文档,看一下允许有多少个有效字符,大多数ANSI编译程序允许有至少31个有效字符。
也就是说,只有变量名或函数名的前31个字符的唯一性会被检查,其余的字符将被忽略掉。
一种较好的经验是使函数名或变量名读起来符合英语习惯,就好象你在读一本书一样——人们应该能读懂你的函数名或变量名,并且能很容易地识别它们并知道它们的大概作用。
请参见:
19.1应该在变量名中使用下划线吗?
19.2可以用变量名来指示变量的数据类型吗?
19.3使用注释会影响程序的速度、大小或效率吗?
19.4使用空白符会影响程序的速度、大小或效率吗?
19.5什么是骆驼式命名法?
19.9一个变量名应该使用多少个字母?
ANSI标准允许有多少个有效字符?
19.10什么是匈牙利式命名法?
应该使用它吗?
19.7. 给函数命名的正确方法是什么?
函数名一般应该以一个动词开始,以一个名词结束,这种方法符合英语的一般规则。
下面列出了几个命名比较合适的函数:
PrintReports();
SpawnUtilityProgram();
ExitSystem();
Initia|izeDisk():
请注意,在这些例子中,函数名都以一个动词开始,以一个名词结束。
如果按英语习惯来读这些函数名,你会发现它们其实就是:
printthereports(打印报告)
spawntheutilityprogram(生成实用程序)
exitthesystem(退出系统)
initializethedisk(初始化磁盘)
使用动词一名词规则(特别是在英语国家)能有效地加强程序的可读性,并且使程序看起来更熟悉。
请参见:
19.5什么是骆驼式命名法?
19.8作用大括号的正确方法是什么?
19.10什么是匈牙利式命名法?
应该使用它吗?
19.8. 使用大括号的正确方法是什么?
在C中,使用大括号的方法无所谓对还是错——只要每个开括号后都有一个闭括号,你的程序中就不再会出现与大括号有关的问题。
然而,有三种著名的大括号格式经常被使用:
Kernighan和Ritchie,Allman,Whitesmiths。
下文中将讨论这三种格式。
在《C程序设计语言(TheCProgrammingLanguage)》一书中,BrianKernighan和DennisRitchie介绍了他们所使用的大括号格式,这种格式如下所示:
if(argc<3){
printf("Error!
Notenougharguments.Correctusageis..\n");
printf("c:
>eopyfile\n");
exit
(1);
}
else{
open_files();
while(!
feof(infile)){
read_data();
write_data();
}
closefiles();
}
注意,在Kb&R格式中,开括号总是与使用它的语句在同一行上,而闭括号总是在它所关闭的语句的下一行上,并且与该语句对齐。
例如,在上例中,if语句的开括号和它在同一行上,|f语句的闭括号在它的下一行上,并且与它对齐。
在与if语句对应的else条件语句以及出现在程序段后部的while语句中,情况也是这样的。
下面是用Allman格式书写的同一个例子:
if(argc<3)
{
printf("Error!
Notenougharguments.Correctusageis:
\n");
printf("C:
>copyfile\n");
exit
(1);
}
else
{
open_files();
while(!
feof(infile))
{
read_data();
writedata();
}
close_files();
}
注意,在Allman格式中,每个大括号都单独成行,并且开括号和闭括号都与使用它们的语句对齐。
下面是用Whitesmiths格式书写的同一个例子:
if(argc<3)
{
printf("Error!
Notenougharguments,Correctusageis:
\n");
printf("C:
>copyfile\n.");
exit
(1);
}
else
{
openfiles();
while(!
feof(infile))
{
read_data();
writedata();
}
closefiles();
}
与Allman格式相同,Whitesmiths格式也要求大括号单独成行,但是它们要和它们所包含的语句对齐。
例如,在上例中,if语句的开括号是与第一个printf()函数调用对齐的。
不管你使用哪一种格式,一定要保持前后一致——这将有助于你自己或其它人更方便地读你的程序。
请参见:
19.5什么是骆驼式命名法?
19.7给函数命名的正确方法是什么?
19.10什么是匈牙利式命名法?
应该使用它吗?
19.9. 一个变量名应该使用多少个字母?
ANSI标准允许有多少个有效字符?
一般说来,变量名或函数名应该足够长,以有效地描述所命名的变量或函数。
应该避免使用短而模糊的名字,因为它们在别人理解你的程序时会带来麻烦。
例如,不要使用象这样的短而模糊的函数名:
opndatfls();
而应该使用更长一些的函数名,象下面这样:
opendata_files();
或者:
OpenDataFiles();
这对变量名也是同样适用的。
例如,与其使用这样一个短而模糊的变量名:
fmem
不如将其扩展为完整的描述:
free_memory_available
使用扩展了的名字会使程序更易读,更易理解。
大多数ANSI编译程序允许有至少31个有效字符——即只有变量或函数名的前31个字符的唯一性会被检查。
一种较好的经验是使函数名或变量名读起来符合英语习惯,就好象你在读一本书一样一人们应该能读懂你的函数名或变量名,并且能很容易地识别它们并知道它们的大概作用。
请参见:
19.1应该在变量名中使用下划线吗?
19.2可以用变量名来指示变量的数据类型吗?
19.5什么是骆驼式命名法?
19.6较长的变量名会影响程序的速度、大小或效率吗?
19.10什么是匈牙利式命名法?
应该使用它吗?
19.10. 什么是匈牙利式命名法?
应该使用它吗?
匈牙利命名法是由Microsoft公司的程序员CharlesSimonyi(无疑是个匈牙利人的后裔)提出的。
在这种命名法中,变量名或函数名要加上一个或两个字符的前缀,用来表示变量或函数的数据类型。
这种命名法有许多好处,它被广泛应用于象MicrosoftWindows这样的环境中。
关于匈牙利命名法的详细解释以及其中的一些命名标准,请参见19.2。
请参见:
19.1应该在变量名中使用下划线吗?
19.2可以用变量名指示变量的数据类型吗?
19.5什么是骆驼式命名法?
19.6较长的变量名会影响程序的速度、大小或效率吗?
19.9一个变量名应该使用多少个字母?
ANSI标准允许有多少个有效字符?
19.11. 什么是重复处理(iterativeprocessing)?
重复处理是指反复执行相同的程序语句,但可能会在满足某个条件时退出循环。
c语言提供了一些现成的结构来实现重复处理,例如while循环,do…while循环和for循环。
在这些结构中,当某个条件为真时,预先定义的一批语句将被反复执行。
下面是一个重复处理的例子:
while(x{
y=O;
do{
for(z=O;z y++;
}while(y<1000);
x++;
}
在这个例子中,包含在while循环中的语句被执行100次,在while循环中还有一个do…while循环,在do…whlie循环中的for循环被执行10次;在for循环中,变量y作100次自增运算。
因此,语句