gpt4 book ai didi

c++ - C++标准:32位和64位的奇怪的有符号/无符号算术除法行为

转载 作者:行者123 更新时间:2023-12-01 14:53:50 25 4
gpt4 key购买 nike

我的代码行为错误。研究它使我得到一个简短的示例,该示例显示了该问题:

//g++  5.4.0

#include <iostream>
#include <vector>

int main()
{
std::vector<short> v(20);

auto D = &v[5] - &v[10];
auto C = D / sizeof(short);

std::cout << "C = " << C;

}

这个例子很常见。它将打印出什么结果?
C = 9223372036854775805

在这里测试: https://rextester.com/l/cpp_online_compiler_gcc
还针对 Clang C++ VS C++ C 进行了测试。结果相同。

与同事讨论时,我指向文件 https://en.cppreference.com/w/cpp/language/operator_arithmetic#Conversions

它说:
  • 如果两个操作数都为有符号或都为无符号,则转换等级较低的操作数将转换为整数转换等级较大的操作数
  • 否则,如果无符号操作数的转换等级大于或等于有符号操作数的转换等级,则将有符号操作数转换为无符号操作数的类型。
  • 否则,如果有符号操作数的类型可以表示无符号操作数的所有值,则无符号操作数将转换为有符号操作数的类型

  • 似乎 第二个规则在这里起作用。但这不是,而是

    为了确认第二个规则,我测试了以下示例:
    //g++  5.4.0
    #include <iostream>

    int main()
    {
    typedef uint32_t u_t; // uint64_t, uint32_t, uint16_t uint8_t
    typedef int32_t i_t; // int64_t, int32_t, int16_t int8_t

    const u_t B = 2;
    const i_t X = -1;

    const i_t A1 = X * B;
    std::cout << "A1 = X * B = " << A1 << "\n";

    const i_t C = A1 / B; // signed / unsigned division
    std::cout << "A1 / B = " << C << "\n";
    }

    使用u_t和i_t的不同等级组合,发现它对于任何组合都可以正常工作,为32位和64位(int64_t / uint64_t和int32_t / uint32_t)。因此,第二个规则不适用于16位和8位。

    注意:乘法运算在所有情况下均能正常工作。因此,这只是除法问题。

    另外, SECOND 规则听起来像是错误的:

    the signed operand is converted to the unsigned operand's type



    已签名不能转换为未签名-这是!错误! 代表值!
    但是相反的转换是正确的-将无符号操作数转换为有符号操作数的类型

    对此我可以注意到,这是C++标准算术运算中可能存在的错误。
    代替:
    Otherwise, if the unsigned operand's conversion rank is greater or equal to the conversion rank of the signed operand, the signed operand is converted to the unsigned operand's type.
    应该是:
    Otherwise, if the signed operand's conversion rank is greater or equal to the conversion rank of the unsigned operand, the unsigned operand is converted to the signed operand's type.
    我认为,如果满足有符号和无符号乘法/除法运算,则无符号操作数将转换为有符号,然后将其强制转换为正确的等级。至少x86汇编器遵循它。

    请告诉我这是哪里错误。我希望这篇文章中的第一个测试对于代替 auto 类型的任何类型都适用,但是现在是而不是类型,并且C++ Standard告诉它这是正确的行为。

    很抱歉提出了一个奇怪的问题,但我对此问题感到困惑。我使用C / C++编写代码已有30年了,但这是我无法明确解释的第一个问题-它是bug还是预期的行为。

    最佳答案

    这里有很多值得一看的地方...由于您忘了实际提出一个问题,我只想谈一谈。

    在第二个代码段中:

    const u_t B = 2;
    const i_t X = -1;
    const i_t A1 = X * B;

    您会发现 A1为-2,并得出结论:在 X * B表达式中,两个操作数都被提升为有符号整数。这不是真的。

    X * B中,按照标准将两个操作数提升为无符号整数,但是随后将其结果转换为带有 const i_t A1 = ...的有符号整数。

    您可以轻松地检查以下内容:
    const u_t B = 2;
    const i_t X = -1;
    const auto A1 = X * B; // unsigned

    您还可以玩 decltype(expression) std::is_signed :

    #include <iostream>
    #include <iomanip>
    #include <type_traits>

    int main()
    {
    signed s = 1;
    unsigned u = 1;
    std::cout << std::boolalpha
    << " signed * signed is signed? " << std::is_signed_v<decltype(s * s)> << "\n"
    << " signed * unsigned is signed? " << std::is_signed_v<decltype(s * u)> << "\n"
    << "unsigned * signed is signed? " << std::is_signed_v<decltype(u * s)> << "\n"
    << "unsigned * unsigned is signed? " << std::is_signed_v<decltype(u * u)> << "\n";
    }

    /*
    signed * signed is signed? true
    signed * unsigned is signed? false
    unsigned * signed is signed? false
    unsigned * unsigned is signed? false
    */

    demo

    关于c++ - C++标准:32位和64位的奇怪的有符号/无符号算术除法行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59597860/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com