改善C++程序的建议:语法篇1

参考自李健的《编写高质量代码--改善C++程序的150个建议》

建议0 不要让main函数返回void

操作系统将main作为程序入口,main函数执行程序代码,最后返回程序的退出状态。但是C++中有一个好坏难定的规定:

在main函数中,return语句用于离开main函数(析构掉所有的具有动态生存时间的对象),并将其返回值作为参数来调用exit函数。如果函数执行到结尾而没有遇到return语 
      句,其效果等同于执行了return 0;。

也就是说编译器会协助完成返回值的问题。

然而,这样的坏处就是,当编译器不支持这个规定的时候,程序就会出错,比如

int main()

{

}

在VC下编译是成功的,在g++下编译,就会提示错误:‘main’必须返回’int‘

建议1 区分0的4个面孔

1 整型0

2 空指针NULL

3 字符串结束标记‘\0‘

‘            \0‘是一个字符,占8位,其二进制位表示是 00000000,在C/C++中,‘\0‘作为字符串的结束标记,是唯一的结束标记

4 逻辑FALSE/false

false/true是标准C++语言里新增的关键字,而FALSE/TRUE是通过#define定义的宏:

#ifndef FALSE

#define FALSE 0

#endif

#ifndef TRUE

#defineTRUE 1

#endif

也就是说FALSE/TRUE是int类型,而false/true是bool型,两者是不一样的,bool在C++里是占用1个字节

建议2 避免那些有运算符引起的混乱

=和==  :在if语句中 比较两个表达式是否相等,

if( nValue == 0)

{  ...  }

如果程序员出现疲劳或精神不集中,把’==‘写成’=‘,这样if(nValue = 0),那么这个if条件是恒成立,并且nValue被赋值为0,并且不会提示错误

这恐怕不是程序员想要的。。。

但如果把常量写在前面,如if(0 == nValue){  },这样如果程序员写成if(0 = nValue){  },编译器会直接的提示错误

但是对于&和&& 、|和|| 这类运算符,就需要平时养成谨慎的习惯了。

建议3 对表达式计算顺序不要向当然

让我们来看一个例子

if(nGrade & MASK == GRAND_ONE)

{...}

我们的本意是,通过nGrade和MASK取与,然后在比较是否等于GRAND_ONE,

可是,实际上上面的代码的真实效果是if( nGrade & (MASK == GRAND_ONE)){}

这个建议的核心是,不要吝啬括号,让语义表达的更准确,这样可以减少出错

如: a = p() + q() * r();

三个函数p() 、q() 、r()的执行顺序可能是6种组合中的一个,所以a的值是不确定的,在这种情况下,就需要明确一种执行顺序,

int x=p();

int y = q();

a = x+y*r();

类似的: expr1 ? expr2 : expr3

建议4 小心宏#define使用中的陷阱

定义宏时,要使用完备的括号:

比如定义两个参数相加, #define ADD(a,b) ((a)+(b))是一个安全的方式

使用宏时,不允许参数发生变化,

定义宏时,用大括号将宏所定义的多条表达式括起来

建议5 不要忘记指针变量的初始化

局部变量的指针未初始化,可能导致程序崩溃

全局变量的指针,编译器会悄悄完成变量的初始化(0)。

建议6 明晰逗号分隔表达式的奇怪之处

      逗号表达式是从C继承来的,其中每个表达式都会被执行,不过,整个表达式的值仅是最右边表达式的结果

如:if(++x,--y,x<20 && y >0),该语句返回的是“ x<20 && y>0”与0比较的结果

另外,逗号表达式既可以用作左值,也可以用作右值。

建议7 时刻提防内存溢出

C语言中的字符串库没有响应的安全保护措施,strcpy、strcat等函数操作时没有检查缓冲区大小,容易引起安全问题

好的方法是,定义一个函数,并传递确定的长度,如:

const int DATA_LENGTH = 16;

void DataCopy(char* src ,int len)

{

char dst[DATA_LENGTH];

for(int i=0;src[i] != 0 && i<DATA_LENGTH; i++)

cout<<src[i]<<endl;

if(len < DATA_LENGTH)

strcpy(dst,src);

}

这里如果,src的长度是10,当i=10时,src[10]就已经越界了。。。

建议8 拒绝晦涩难懂的函数指针

比如 void (*p[10])  (void  (*)() );

1 声明一个无参数、返回空的函数指针的typedef,如:typedef void (*pfv)();

2 声明一个指向参数为pfv且返回空的函数指针, 如 : typedef  void (*pFun_taking_pfv) (pfv));

3 定义数组,pFun_taking_pfv p[10];

建议9 防止头文件重发包含

      方式一:

#ifndef __TEST_H__

#define __TEST_H__

......

#endif

方式二:

#pragma once

优缺点:方式一的缺点是宏导致的编译时间长

方式二的缺点是只是针对物理路径相同的文件,而不是文件的内容

时间: 2024-12-14 04:13:06

改善C++程序的建议:语法篇1的相关文章

[转]改善C#程序的建议4:C#中标准Dispose模式的实现

需要明确一下C#程序(或者说.NET)中的资源.简单的说来,C#中的每一个类型都代表一种资源,而资源又分为两类: 托管资源:由CLR管理分配和释放的资源,即由CLR里new出来的对象: 非托管资源:不受CLR管理的对象,windows内核对象,如文件.数据库连接.套接字.COM对象等: 毫无例外地,如果我们的类型使用到了非托管资源,或者需要显式释放的托管资源,那么,就需要让类型继承接口IDisposable.这相当于是告诉调用者,该类型是需要显式释放资源的,你需要调用我的Dispose方法. 不

改善C#程序的建议2:C#中dynamic的正确用法

原文:改善C#程序的建议2:C#中dynamic的正确用法 dynamic是FrameWork4.0的新特性.dynamic的出现让C#具有了弱语言类型的特性.编译器在编译的时候不再对类型进行检查,编译期默认dynamic对象支持你想要的任何特性.比如,即使你对GetDynamicObject方法返回的对象一无所知,你也可以像如下那样进行代码的调用,编译器不会报错: dynamic dynamicObject = GetDynamicObject(); Console.WriteLine(dyn

改善C#程序的建议4:C#中标准Dispose模式的实现

原文:改善C#程序的建议4:C#中标准Dispose模式的实现 需要明确一下C#程序(或者说.NET)中的资源.简单的说来,C#中的每一个类型都代表一种资源,而资源又分为两类: 托管资源:由CLR管理分配和释放的资源,即由CLR里new出来的对象: 非托管资源:不受CLR管理的对象,windows内核对象,如文件.数据库连接.套接字.COM对象等: 毫无例外地,如果我们的类型使用到了非托管资源,或者需要显式释放的托管资源,那么,就需要让类型继承接口IDisposable.这相当于是告诉调用者,该

改善C#程序的建议1:非用ICloneable不可的理由

原文:改善C#程序的建议1:非用ICloneable不可的理由 好吧,我承认,这是一个反标题,实际的情况是:我找不到一个非用ICloneable不可的理由.事实上,接口ICloneable还会带来误解,因为它只有一个Clone方法. 我们都知道,对象的拷贝分为:浅拷贝和深拷贝.ICloneable仅有一个Clone方法使我们无法从命名的角度去区分到底是哪个拷贝. 浅拷贝:将对象的字段复制到副本(新的对象)中,同时将字段的值也赋值过去,但是引用类型字段只复制引用,而不是引用类型本身.这意味着,源对

编写高质量代码–改善python程序的建议(二)

原文发表在我的博客主页,转载请注明出处! 建议七:利用assert语句来发现问题断言(assert)在很多语言中都存在,它主要为调试程序服务,能够快速方便地检查程序的异常或者发现不恰当的输入等,可防止意想不到的情况出现.其语法如下: assert expression1 ["," expression2] 其中expression1的值会返回True或者False,当值为False的时候会引发AssertionError,而expression2是可选的,常用来传递具体的异常信息. 不

改善C#程序的建议9:使用Task代替ThreadPool和Thread

一:Task的优势 ThreadPool相比Thread来说具备了很多优势,但是ThreadPool却又存在一些使用上的不方便.比如: 1: ThreadPool不支持线程的取消.完成.失败通知等交互性操作: 2: ThreadPool不支持线程执行的先后次序: 以往,如果开发者要实现上述功能,需要完成很多额外的工作,现在,FCL中提供了一个功能更强大的概念:Task.Task在线程池的基础上进行了优化,并提供了更多的API.在FCL4.0中,如果我们要编写多线程程序,Task显然已经优于传统的

【转】改善C#程序的建议2:C#中dynamic的正确用法 空间

dynamic是FrameWork4.0的新特性.dynamic的出现让C#具有了弱语言类型的特性.编译器在编译的时候不再对类型进行检查,编译期默认dynamic对象支持你想要的任何特性.比如,即使你对GetDynamicObject方法返回的对象一无所知,你也可以像如下那样进行代码的调用,编译器不会报错: dynamic dynamicObject = GetDynamicObject();Console.WriteLine(dynamicObject.Name);Console.WriteL

编写高质量代码之改善C++程序语法篇2&lt;从C到C++需要做的改变&gt;

偶然发现网络读书频道,http://book.51cto.com/art/201202/317549.htm,挺不错的希望CSDN也有,可能已经有了... 阅读<编写高质量代码--改善C++程序的150个建议>,总结归纳: 此文用以加深记忆,督促学习的目的 0  在C++中如何使用C的代码 如:int func( int a, char b); c编译函数时不带函数的类型信息,上面的函数被编译成类似_Func的符号 c++为了实现重载,在编译时会加上函数的参数类型,上面的函数会被编译成类似_F

转载-------编写高质量代码:改善Java程序的151个建议(第1章:JAVA开发中通用的方法和准则___建议1~5)

阅读目录 建议1:不要在常量和变量中出现易混淆的字母 建议2:莫让常量蜕变成变量 建议3:三元操作符的类型务必一致 建议4:避免带有变长参数的方法重载 建议5:别让null值和空值威胁到变长方法              The reasonable man adapts himself to the world; The unreasonable one persists in trying to adapt the world himself. 明白事理的人使自己适应世界:不明事理的人想让世