【问题标题】:C++ type conversion precedence in a return返回中的 C++ 类型转换优先级
【发布时间】:2014-07-05 04:11:45
【问题描述】:

我有一个代码被更改为在 64 位模式下编译,而之前由于各种原因它是在 Win32 中编译的。这导致了一些清理工作以解决一些警告,因此我正在挑选代码并发现如下所示:

class foo 
{

public:
    int foo() { return data_.size()-1; }

private:
    std::vector<int> data_;
};

STL 容器上的 size() 方法返回无符号值。返回值被转换为有符号整数值,因此在某些时候会发生转换。

我不确定这里的优先级。 size() 返回的值是否会被强制转换为 int,然后减去 1,如果 size 为零,这将导致返回值为 -1?或者我们会从 unsigned int 中减去 1,如果调用它时容器为空,可能会做坏事?

谢谢!

【问题讨论】:

  • 它将是无符号的 = 无符号的 - 1;返回有符号(无符号) 其中无符号(0) - 1 == 无符号(最大值)

标签: c++ types stl casting type-conversion


【解决方案1】:

它将是无符号的 = 无符号的 - 1;返回有符号(无符号) 其中无符号(0) - 1 == 无符号(最大值)

从 4.7 积分转换开始

整数类型的纯右值可以转换为另一个纯右值 整数类型。无作用域枚举类型的纯右值可以是 转换为整数类型的纯右值。如果目标类型是 无符号,结果值是最小无符号整数全等 到源整数(模 2n 其中 n 是用于 表示无符号类型)。 [注:在二进制补码中 表示,这种转换是概念性的,没有变化 在位模式中(如果没有截断)。 — 尾注] 如果 目标类型有符号,如果可以,则值不变 以目标类型(和位域宽度)表示;否则, 该值是实现定义的。

因此,任何大于最大有符号值的无符号值都会导致实现定义的行为。

【讨论】:

    【解决方案2】:

    如果大小为 0,则结​​果不是 -1,而是一个非常大的整数“18446744073709551615”(无符号(最大值))。

    #include <vector>
    #include <iostream>
    
    int main()
    { 
        std::vector<int> nums {};
    
        std::cout << "nums contains " << nums.size()-1 << " elements.\n";
        // nums contains 18446744073709551615 elements.
    }
    

    http://coliru.stacked-crooked.com/a/a69d4af99ba77f47

    【讨论】:

    • 此链接已转换为 int。
    • 看看我的链接。我添加了对int 的转换(就像OP 一样)并得到-1
    • 是的,它是正确的。您将类型转换从 unsigned int 添加到 int。原始代码有return data_.size()-1;,没有强制转换。所以在空向量中调用 data_.size() 的情况下,你会得到一个更大的数字(无符号(最大))。
    • 在两个版本的示例中,您都可以获得最大 int 值。在 32 位版本中,您得到 2^32 -1 = 4294967295,在 64 位版本中,您得到 2^64 - 1 = 18446744073709551615
    【解决方案3】:

    data_.size()-1 被评估为无符号整数时。当data_.size()0 时,该函数可能会返回一个非常大的正数,而不是-1

    您的最佳选择:

    int foo() { int s = data_.size(); return s-1; }
    

    【讨论】:

      【解决方案4】:

      下一个程序返回i=-1std::numeric_limits&lt;unsigned&gt;::max() 的位模式是int -1 之一。这就是您的代码在 w32 中工作的原因。

      #include <iostream>
      #include <limits>
      
      int main() {
        std::cout << "i=" << static_cast<int>(std::numeric_limits<unsigned>::max()) << '\n';
      }
      
      /*
        Local Variables:
        compile-command: "g++ test.cc -o a.exe && ./a.exe"
        End:
      */
      

      但是,您的代码依赖于有符号整数类型和无符号整数类型的转换。类型必须适合!因此,最好使用std::ptrdiff_tstd::size_t

      #include <iostream>
      #include <limits>
      
      int main() {
        std::cout << "i=" << static_cast<std::ptrdiff_t>(std::numeric_limits<std::size_t>::max()) << '\n';
      }
      
      /*
        Local Variables:
        compile-command: "g++ test.cc -o a.exe && ./a.exe"
        End:
      */
      

      【讨论】:

        【解决方案5】:

        你的第二个猜测是正确的。一般来说,评估表单的任何表达式

        exp1 op exp2
        

        按步骤工作

        1. 评估exp1
        2. 评估exp2
        3. op 应用于exp1exp2 的值

        注意:步骤 1 和 2 可以按任何顺序进行。重点是在应用运算符之前评估每个操作数

        所以在这种情况下,exp1 将首先评估为unsigned int 值,并且可能会产生不良影响。

        【讨论】:

        • Exp2 可以先求值。
        猜你喜欢
        • 2011-03-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-01-12
        • 2012-04-13
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多