龙盟编程博客 | 无障碍搜索 | 云盘搜索神器
快速搜索
主页 > 软件开发 > C/C++开发 >

C++编译器无法捕捉到的8种错误实例分析(2)

时间:2014-09-05 02:24来源:网络整理 作者:网络 点击:
分享到:
如果操作数是整数类型,除法操作将丢弃任何小数部分,并只返回整数部分。 int nX = 7;int nY = 2;int nValue = nX / nY; // nValue = 3 如果一个操作数是整型,另一个

如果操作数是整数类型,除法操作将丢弃任何小数部分,并只返回整数部分。

int nX = 7;
int nY = 2;
int nValue = nX / nY;  // nValue = 3

如果一个操作数是整型,另一个操作数是浮点型,则整型会提升为浮点型:

float fX = 7.0;
int nY = 2;
float fValue = fX / nY;
 
// nY 提升为浮点型,除法操作将返回浮点型值
// fValue = 3.5

有很多新手程序员会尝试写下如下的代码:

int nX = 7;
int nY = 2;
float fValue = nX / nY; // fValue = 3(不是3.5哦!)

这里的本意是nX/nY将产生一个浮点型的除法操作,因为结果是赋给一个浮点型变量的。但实际上并非如此。nX/nY首先被计算,结果是一个整型值,然后才会提升为浮点型并赋值给fValue。但在赋值之前,小数部分就已经丢弃了。

要强制两个整数采用浮点型除法,其中一个操作数需要类型转换为浮点数:

int nX = 7;
int nY = 2;
float fValue = static_cast<float>(nX) / nY; // fValue = 3.5

因为nX显式的转换为float型,nY将隐式地提升为float型,因此除法操作符将执行浮点型除法,得到的结果就是3.5。

通常一眼看去很难说一个除法操作符究竟是执行整数除法还是浮点型除法:

z = x / y; // 这是整数除法还是浮点型除法?

但采用匈牙利命名法可以帮助我们消除这种疑惑,并阻止错误的发生:

int nZ = nX / nY;   // 整数除法
double dZ = dX / dY; // 浮点型除法

有关整数除法的另一个有趣的事情是,当一个操作数是负数时C++标准并未规定如何截断结果。造成的结果就是,编译器可以自由地选择向上截断或者向下截断!比如,-5/2可以既可以计算为-3也可以计算为-2,这和编译器是向下取整还是向0取整有关。大多数现代的编译器是向0取整的。

3)=  vs  ==

这是个老问题,但很有价值。许多C++新手会弄混赋值操作符(=)和相等操作符(==)的意义。但即使是知道这两种操作符差别的程序员也会犯下键盘敲击错误,这可能会导致结果是非预期的。

// 如果nValue是0,返回1,否则返回nValue
int foo(int nValue)
{
  if (nValue = 0) // 这是个键盘敲击错误 !
    return 1;
  else
    return nValue;
}
 
int main()
{
  std::cout << foo(0) << std::endl;
  std::cout << foo(1) << std::endl;
  std::cout << foo(2) << std::endl;
 
  return 0;
}

函数foo()的本意是如果nValue是0,就返回1,否则就返回nValue的值。但由于无意中使用赋值操作符代替了相等操作符,程序将产生非预期性的结果:

0
0
0

当foo()中的if语句执行时,nValue被赋值为0。if (nValue = 0)实际上就成了if (nValue)。结果就是if条件为假,导致执行else下的代码,返回nValue的值,而这个值刚好就是赋值给nValue的0!因此这个函数将永远返回0。

在编译器中将告警级别设置为最高,当发现条件语句中使用了赋值操作符时会给出一个警告信息,或者在条件判断之外,应该使用赋值操作符的地方误用成了相等性测试,此时会提示该语句没有做任何事情。只要你使用了较高的告警级别,这个问题本质上都是可修复的。也有一些程序员喜欢采用一种技巧来避免=和==的混淆。即,在条件判断中将常量写在左边,此时如果误把==写成=的话,将引发一个编译错误,因为常量不能被赋值。

4)混用有符号和无符号数

如同我们在整数除法那一节中提到的,C++中大多数的二元操作符需要两端的操作数是同一种类型。如果操作数是不同的类型,其中一个操作数将提升自己的类型以匹配另一个操作数。当混用有符号和无符号数时这会导致出现一些非预期性的结果!考虑如下的例子:

cout << 10 – 15u; // 15u是无符号整数

有人会说结果是-5。由于10是一个有符号整数,而15是无符号整数,类型提升规则在这里就需要起作用了。C++中的类型提升层次结构看起来是这样的:

精彩图集

赞助商链接