我有以下示例,在VS2005中编译,警告级别4:
int main(int argc, char *argv[])
{
short s = 2;
short t = 3;
t *= s; // warning C4244: '*=' : conversion from 'int' to 'short', possible loss of data
t = t * s;
}
在我看来,任何一条线路都不应该有警告。
* =出于某种原因是否创建了对int的隐式转换?
编辑:
似乎第二行(以及在VS2008中)缺少警告是真正的问题。
感谢您的回答。
答案 0 :(得分:12)
是。 C ++中的所有算术运算符都在int
和更宽的范围内定义。当您将两个short
相乘时(如果您使用*
或*=
无关紧要),它们将首先转换为int
。这由ISO C ++ 5 [expr] / 9:
许多期望算术或枚举类型操作数的二元运算符会以类似的方式导致转换并产生结果类型。目的是产生一个通用类型,它也是结果的类型。这种模式称为通常的算术转换,定义如下:
- 如果任一操作数的类型为long double,则另一个操作数应转换为long double。
- 否则,如果任一操作数为double,则另一个操作数应转换为double。
- 否则,如果任一操作数为float,则另一操作数应转换为float。
- 否则,应对两个操作数执行整体促销(4.5)。
- 然后,如果任一操作数是无符号长的,则另一个操作数应转换为无符号长。
- 否则,如果一个操作数是long int而另一个是unsigned int,那么如果long int可以表示unsigned int的所有值,则unsigned int应该转换为long int;否则两个操作数都应转换为unsigned long int。
- 否则,如果任一操作数为long,则另一个操作数应转换为long。
- 否则,如果任一操作数是无符号的,则另一个操作数应转换为无符号。
[注意:否则,唯一剩下的情况是两个操作数都是int]
和4.5 [conv.prom]:
1如果int可以表示源类型的所有值,则可以将char,signed char,unsigned char,short int或unsigned short int类型的rvalue转换为int类型的rvalue。否则,源rvalue可以转换为unsigned int类型的右值。
2类型为wchar_t(3.9.1)或枚举类型(7.2)的rvalue可以转换为以下第一种类型的rvalue,它可以表示其基础类型的所有值:int,unsigned int,长或无符号长。
3如果int可以表示位域的所有值,则可以将积分位域(9.6)的rvalue转换为int类型的rvalue;否则,如果unsigned int可以表示位字段的所有值,则可以将其转换为unsigned int。如果位字段较大,则不适用整数提升。如果位字段具有枚举类型,则将其视为该类型的任何其他值以用于促销目的。
4 bool类型的rvalue可以转换为int类型的rvalue,false变为0,true变为1。
5这些转换称为整体促销。
然而,为什么它只在一行上发出警告但不是两者都不清楚。
答案 1 :(得分:4)
short * short的结果可能会溢出short,因此它可能会在第二个示例中将中间结果存储在int中。如果他们两个都应该有警告。
第一个可能是抱怨,因为它将结果直接存储在原始短值中,而第二个是创建一个中间int然后将其转换为short(仍然是一个有损操作,但许多编译器不会抱怨)。
答案 2 :(得分:3)
答案 3 :(得分:0)
这似乎是一个非常奇怪的警告。一些观察:
short s = 12345;
s *= 0xffff; // no warning
s *= (int)0xffff; // no warning
s *= 0x10000; // C4244
s *= -0x8000; // no warning
s *= -0x8001; // C4244
short t = -12345;
s *= t; // no warning
s *= (int)t; // no warning
s *= (unsigned)t; // no warning
s *= (int)t * 0xffff; // no warning
s *= (int)t * 0x10000; // C4244
它似乎并不关心特定的运算符 - 所有+-*/
都给出了相同的结果。它似乎实际上并没有单独查看表达式类型,而是在涉及的文字中,并且一旦超过魔法阈值,警告就会弹出。