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

时间:2008-10-29 03:55:07

标签: c++ c casting

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

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;

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

9 个答案:

答案 0 :(得分:26)

问题1:浮动部门

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

问题2:编译器如何工作

要记住的五条经验法则:

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

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

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

溢出

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

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

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

答案 1 :(得分:13)

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

If one number is...   And the other is...    The compiler will promote to...
-------------------   -------------------    -------------------------------
char                  int                    int
signed                unsigned               unsigned
char or int           float                  float
float                 double                 double

示例:

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

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

4.0 + 5/3  =  4.0 + 1 = 5.0

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

答案 2 :(得分:5)

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

每当类型不匹配时,“较小”类型会自动提升为“较大”类型,浮点数比整数类型“大”。

答案 3 :(得分:2)

整数除法:强制转换任何一个操作数,不需要同时转换它们。如果两个操作数都是整数,则除法运算是整数除法,否则它是浮点除法。

至于溢出问题,不需要显式转换,因为编译器会隐式地为你执行此操作:

#include <iostream>
#include <limits>

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

答案 4 :(得分:1)

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

话虽如此,无论如何,我总是将两者都放到一个浮子上。

答案 5 :(得分:1)

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

所以全部:

float c =(float)a / b;

float c = a /(float)b;

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

会有相同的结果。

答案 6 :(得分:1)

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

这样的东西
int a;
int b;
float z;

z = a*1.0*b;

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

答案 7 :(得分:1)

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

答案 8 :(得分:0)

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

e.g。这个cast float-&gt; int很明显。

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