在C / C ++中进行数学运算时,我应该对哪些变量进行类型转换?

例如,当我划分两个整数并希望返回一个浮点数时,我迷信地写了这样的东西:

int a = 2, b = 3; float c = (float)a / (float)b; 

如果我不将ab为浮点数,它将执行整数除法并返回一个int。

类似地,如果我想将带符号的8位数与无符号8位数相乘,我会在乘法之前将它们转换为有符号的16位数,以免出现溢出:

 u8 a = 255; s8 b = -127; s16 = (s16)a * (s16)b; 

在完全不进行转换或仅转换其中一个变量时,编译器在这些情况下的行为究竟如何? 我是否真的需要显式地转换所有变量,或者只是左边的那个变量,还是右边的变量?

问题1:浮动部门

 int a = 2, b = 3; float c = static_cast(a) / b; // need to convert 1 operand to a float 

问题2:编译器的工作原理

要记住的五条经验法则:

  • 始终对相同类型的值执行算术运算。
  • 结果类型与操作数相同(促销后)
  • 在int上执行最小类型算术运算。
  • ANSCI C(以及C ++)使用值保留整数提升。
  • 每个操作都是孤立完成的

ANSI C规则如下:
这些规则中的大多数也适用于C ++,但并非所有类型都得到官方支持(尚未)。

  • 如果任一操作数是long double,则另一个操作数转换为long double
  • 如果任一操作数是double,则另一个操作数转换为double
  • 如果任一操作数是浮点数,则另一个操作数转换为浮点数
  • 如果任一操作数是无符号长long,则另一个操作数转换为无符号long long
  • 如果任一操作数为long long,则另一操作数转换为long long
  • 如果任一操作数是无符号长整数,则另一个操作数转换为无符号长整数
  • 如果任一操作数为long,则另一操作数转换为long
  • 如果任一操作数是unsigned int,则另一个操作数转换为unsigned int
  • 否则两个操作数都转换为int

溢出

溢出始终是一个问题。 注意。 结果的类型与输入操作数相同,因此所有操作都可以溢出,所以是的,你需要担心它(尽管语言没有提供任何明确的方法来捕捉这种情况。

作为旁注:
无符号除法不能溢出但签名除法可以。

 std::numeric_limits::max() / -1 // No Overflow std::numeric_limits::min() / -1 // Will Overflow 

通常,如果操作数具有不同的类型,则编译器会将所有操作数提升为最大或最精确的类型:

如果一个数字是...而另一个是...编译器将促进...
 ------------------- ------------------- ------------ -------------------
 char int int
签名无符号无符号
 char或int float float
浮双倍

例子:

 char + int ==> int
 signed int + unsigned char ==> unsigned int
 float + int ==> float

但请注意,促销只在每次中间计算时才会发生,因此:

  4.0 + 5/3 = 4.0 + 1 = 5.0 

这是因为首先执行整数除法,然后将结果提升为浮点以进行加法。

你可以投出其中一个。 不过哪一个并不重要。

只要类型不匹配,“较小”类型就会自动提升为“较大”类型,浮点数比“整数”类型“大”。

整数划分:投射任何一个操作数,无需将它们都投射。 如果两个操作数都是整数,则除法运算是整数除法,否则它是浮点除法。

至于溢出问题,没有必要显式转换,因为编译器隐式为您执行此操作:

 #include  #include  using namespace std; int main() { signed int a = numeric_limits::max(); unsigned int b = a + 1; // implicit cast, no overflow here cout << a << ' ' << b << endl; return 0; } 

在浮点除法的情况下,只要一个变量是浮点数据类型(float或double),那么另一个变量应该扩展为浮点类型,并且应该发生浮点除法; 所以没有必要将两者都投入浮动。

话虽如此,无论如何,我总是把它们都扔到浮子上。

我认为只要你只是投射两个变量中的一个,编译器就会正常运行(至少在我知道的编译器上)。

所以全部:

float c =(float)a / b;

float c = a /(float)b;

float c =(float)a /(float)b;

会有相同的结果。

然后有像我这样的老脑损坏类型,不得不使用老式语言,只是不假思索地写出类似的东西

 int a; int b; float z; z = a*1.0*b; 

当然这不是普遍的,仅仅适用于这种情况。

在安全关键系统上工作之后,我倾向于偏执并且总是抛出两个因素:浮动(a)/浮动(b) – 以防万一有些微妙的陷阱计划在以后咬我。 无论编译器有多好,无论官方语言规范中的细节有多清楚。 偏执狂:程序员最好的朋友!

你需要投射一两面吗? 答案不是由编译器决定的。 它必须知道准确的预防规则。 相反,答案应该由稍后阅读代码的人决定。 仅仅因为这个原因,将两侧都放在同一类型上。 隐式截断可能足够明显,因此强制转换可能是多余的。

例如,这个cast float-> int是显而易见的。

 int a = float(foo()) * float(c);