C++ - 数值比较numerical comparison

在工作碰到好几次不同type的integer/value比较出错,导致奇怪的bug。很小的问题,却不容忽视。

看几个例子.原来我的想法是他们bitwise level是一样的,这4个比较应该都是true才对。

char  m_costBasis1;
UINT1 m_costBasis2;//define unsigned char UINT1
UINT2 l_BasisNum; //define unsigned short UINT2

如果assign 2给这三个变量
m_costBasis1 == l_BasisNum //true
m_costBasis2 == l_BasisNum //true

如果assign 176给这三个变量 (>=127)
m_costBasis1 == l_BasisNum //false (-80 vs 176)
m_costBasis2 == l_BasisNum //true


安全的做法,当然是避免这种相同意义的东西有不同type的定义。不过木已成舟,如果这种定义来自数据库,很可能就改不了了;一个可以的work around是做explicit convert。

但是windows上的compiler为什么跟我想的不一样呢?在说答案之前,先上点原理。


为了提高本帖的理论深度和技术含量,贴上几段关于implicit numberical convert的权威说明。具体说明了convert的几条原则以及他们间的优先级。

http://en.cppreference.com/w/cpp/language/implicit_cast

Integral promotion

Prvalues of small integral types (such as char) may be converted to prvalues of larger integral types (such asint). In particular,arithmetic operators do not accept types smaller than int as arguments, and integral promotions are automatically applied. This conversion always preserves the value.

The following implicit conversions are classified as integral promotions:

  • signed char or signed short can be converted toint.
  • unsigned char or unsigned short can be converted toint if it can hold its entire value range, andunsignedint otherwise.
  • char can be converted to int orunsignedint depending on the underlying type: signed char or unsignedchar (see above)


http://en.cppreference.com/w/cpp/language/operator_arithmetic

the operand has integer type (because bool, char, char16_t, char32_t, wchar_t, and unscoped enumeration were promoted at this point) andintegral conversions are applied to produce the common type, as follows:

  • If both operands are signed or both are unsigned, the operand with lesser conversion rank is converted to the operand with the greater integer conversion rank
  • Otherwise, if the unsigned operand's conversion rank is greater or equal to the conversion rank of the signed operand, the signed operand is converted to the unsigned operand's type.
  • Otherwise, if the signed operand's type can represent all values of the unsigned operand, the unsigned operand is converted to the signed operand's type
  • Otherwise, both operands are converted to the unsigned counterpart of the signed operand's type.

The conversion rank above increases in order bool,signedchar, short,int,long,longlong. The rank of any unsigned type is equal to the rank of the corresponding signed type. The rank ofchar is equal to the rank ofsignedchar and unsignedchar. The ranks of char16_t,char32_t, andwchar_t are equal to the ranks of their underlying types.


http://en.cppreference.com/w/cpp/language/operator_comparison

Arithmetic comparison operators

If the operands has arithmetic or enumeration type (scoped or unscoped), usual arithmetic conversions are performed following the rules for arithmetic operators. The values are compared after conversions:


以上说的是standard的convert的原则,但是microsoft的实现是不一样的;看下面。


http://msdn.microsoft.com/en-us/library/09ka8bxx%28v=vs.100%29.aspx

Arithmetic Conversions

  • If the preceding three conditions are not met, and if either operand is of typeunsigned int, the other operand is converted to typeunsigned int.

  • If none of the preceding conditions are met, both operands are converted to typeint.

如果看完上面的,估计你也知道答案了。 

按照cppreference的说法,这4处确实都是true的,因为会promote成unsigned int;

但是miscrosoft的做法,比较简单,都是int。所以char中的-80(就是unsigned short的176)会变成-80的int;但是176的unsigned short变成176的int,当然有false的情况。



你可能感兴趣的:(C++,教训)