C++中的大多数二元操作都要求两个操作数是同一类型。如果操作数的不同类型,其中一个操作数会提升到和另一个操作数相匹配的类型。在 C++ 中,除法操作符可以被看做是 2 个不同的操作:其中一个操作于整数之上,另一个是操作于浮点数之上。如果操作数是浮点数类型,除法操作将返回一个浮点数的值:
float fX = 7; float fY = 2; float fValue = fX / fY; // fValue = 3.5
如果操作数是整数类型,除法操作将丢弃任何小数部分,并只返回整数部分。
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)混用有符号和无符号数