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

2021-12-31 00:00:00 c casting c++

例如,当我将两个整数相除并希望返回一个浮点数时,我迷信地这样写:

For example, when I'm dividing two ints and want a float returned, I superstitiously write something like this:

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

如果我不将 ab 转换为浮点数,它将进行整数除法并返回一个 int.

If I do not cast a and b to floats, it'll do integer division and return an int.

同样,如果我想将一个有符号的 8 位数字与一个无符号的 8 位数字相乘,我会在相乘之前将它们强制转换为有符号的 16 位数字,以免溢出:

Similarly, if I want to multiply a signed 8-bit number with an unsigned 8-bit number, I will cast them to signed 16-bit numbers before multiplying for fear of overflow:

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

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

How exactly does the compiler behave in these situations when not casting at all or when only casting one of the variables? Do I really need to explicitly cast all of the variables, or just the one on the left, or the one on the right?

推荐答案

问题一:浮点除法

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

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

要记住的五个经验法则:

Question 2: How the compiler works

Five rules of thumb to remember:

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

ANSI C 规则如下:
大多数这些规则也适用于 C++,尽管并非所有类型都得到官方支持(目前).

The ANSI C rules are as follows:
Most of these rules also apply to C++ though not all types are officially supported (yet).

  • 如果任一操作数是 long double,另一个操作数将转换为 long double.
  • 如果任一操作数是 double,则另一个将转换为 double.
  • 如果其中一个操作数是 float,另一个将转换为 float.
  • 如果其中一个操作数是 unsigned long long,另一个将转换为 unsigned long long.
  • 如果其中一个操作数是 long long,另一个将转换为 long long.
  • 如果其中一个操作数是 unsigned long,另一个将转换为 unsigned long.
  • 如果任一操作数是 long,另一个将转换为 long.
  • 如果其中一个操作数是 unsigned int,另一个将转换为 unsigned int.
  • 否则两个操作数都被转换为int.
  • If either operand is a long double the other is converted to a long double.
  • If either operand is a double the other is converted to a double.
  • If either operand is a float the other is converted to a float.
  • If either operand is a unsigned long long the other is converted to unsigned long long.
  • If either operand is a long long the other is converted to long long.
  • If either operand is a unsigned long the other is converted to unsigned long.
  • If either operand is a long the other is converted to long.
  • If either operand is a unsigned int the other is converted to unsigned int.
  • Otherwise both operands are converted to int.

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

Overflow is always a problem. Note. The type of the result is the same as the input operands so all the operations can overflow, so yes you do need to worry about it (though the language does not provide any explicit way to catch this happening.

附注:
无符号除法不能溢出,但有符号除法可以.

As a side note:
Unsigned division can not overflow but signed division can.

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

相关文章