【问题标题】:Which variables should I typecast when doing math operations in C/C++?在 C/C++ 中进行数学运算时,我应该对哪些变量进行类型转换?
【发布时间】:2008-10-29 03:55:06
【问题描述】:

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

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;

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

【问题讨论】:

    标签: c++ c casting


    【解决方案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
    • 如果任一操作数是 unsigned long long,则另一个操作数将转换为 unsigned long long
    • 如果任一操作数为 long long,则另一个操作数将转换为 long long
    • 如果任一操作数是 unsigned long,则另一个操作数将转换为 unsigned long
    • 如果任一操作数为 long,则另一个操作数将转换为 long
    • 如果任一操作数是 unsigned int,则另一个操作数将转换为 unsigned int
    • 否则两个操作数都被转换为int

    溢出

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

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

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

    【讨论】:

    • 不错的概述 - 也许使用术语“提升”iso“转换”?
    • “溢出总是一个问题”。除了你真正想要的模数运算这种千载难逢的情况。
    【解决方案2】:

    一般来说,如果操作数属于不同类型,编译器会将所有操作数提升为最大或最精确的类型:

    如果一个数字是……而另一个是……编译器将提升为…… -------------------- -------- ------------ ------------------ char int int 有符号 无符号 无符号 char 或 int float 浮点数 浮动双双

    例子:

    字符 + 整数 ==> 整数 有符号整数 + 无符号字符 ==> 无符号整数 浮点数 + 整数 ==> 浮点数

    但请注意,提升仅在每次中间计算所需时发生,因此:

    4.0 + 5/3 = 4.0 + 1 = 5.0

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

    【讨论】:

    • 我想你的意思是“有符号 + 无符号 = 有符号”?
    • Kasprzol:规则将有符号变量提升为无符号变量;推广一般是从小到大类型,然后从有符号到无符号。
    【解决方案3】:

    你可以只施放其中一个。不管是哪一个。

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

    【讨论】:

      【解决方案4】:

      整数除法:转换任意一个操作数,无需同时转换。如果两个操作数都是整数,则除法运算为整数除法,否则为浮点除法。

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

      #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;
      }
      

      【讨论】:

        【解决方案5】:

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

        话虽如此,无论如何,我总是将两者都转换为浮点数。

        【讨论】:

          【解决方案6】:

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

          所以所有的:

          float c = (float)a / b;

          float c = a / (float)b;

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

          会有同样的结果。

          【讨论】:

            【解决方案7】:

            还有像我这样的老脑残类型,不得不使用老式语言,只是不假思索地写出类似

            的东西
            int a;
            int b;
            float z;
            
            z = a*1.0*b;
            

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

            【讨论】:

              【解决方案8】:

              在安全关键系统上工作过,我倾向于偏执并总是同时考虑两个因素:float(a)/float(b) - 以防万一以后有一些微妙的陷阱计划咬我。无论编译器被认为有多好,无论官方语言规范中的细节定义多么明确。妄想症:程序员最好的朋友!

              【讨论】:

                【解决方案9】:

                您需要投射一侧还是两侧?答案不是由编译器决定的。它必须知道确切的、精确的规则。相反,答案应该由稍后阅读代码的人来决定。仅出于这个原因,将双方都转换为相同的类型。隐式截断可能足够明显,因此强制转换可能是多余的。

                例如这个 cast float->int 很明显。

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

                【讨论】:

                  猜你喜欢
                  • 2011-05-06
                  • 1970-01-01
                  • 2015-10-10
                  • 1970-01-01
                  • 2012-05-12
                  • 2016-01-20
                  • 1970-01-01
                  • 1970-01-01
                  • 2011-08-18
                  相关资源
                  最近更新 更多