【问题标题】:subtraction of two unsigned gives signed两个无符号的减法得到有符号
【发布时间】:2016-01-02 18:09:44
【问题描述】:

我有以下代码:

#include <cstdint>

template <typename T>
T test(T a, T b)
{
    float aabb = reinterpret_cast<float>(a - b);
}

int main(int argc, const char *argv[])
{
    std::uint8_t a8, b8;
    test(a8, b8);
    return 0;
}

我知道reinterpret_cast&lt;float&gt; 无法工作,并且在编译时会出错。我正在使用该错误,以便编译器告诉我a - b 的类型。

问题在于,在这种情况下,当a - b 的类型都是int 时,它们都是uint8_t (unsigned char)uint16_t 也是如此。但不是uint32_t,它说a - bunsigned int

所以,我的问题是:这是预期的行为(unsigned char - unsigned char 给出一个 int),还是某种奇怪的编译器错误(用 GCC 和 clang 测试)?

【问题讨论】:

  • 这似乎是relevant(促销至少在C和C++中是相似的,如果不一样的话)。
  • 是的,任何小于int 的类型都会提升为int 进行算术运算。
  • 还要避免reinterpret_cast,它是实现定义的。

标签: c++


【解决方案1】:

是的,这是预期的,作为所谓的常规算术转换积分提升规则相结合的一部分。

C++03 和 C++11 之间的确切措辞发生了变化,但在这种情况下最终结果是相同的。


[C++03: 4.5/1]: 如果int 可以表示所有源类型;否则,源右值可以转换为 unsigned int 类型的右值。

[C++03: 4.5/5]: 这些转化称为整体促销

[C++03: 5/9]: 许多期望算术或枚举类型操作数的二元运算符会导致转换并以类似方式产生结果类型。目的是产生一个通用类型,也就是结果的类型。

这种模式称为常用的算术转换,定义如下:

  • 如果任一操作数的类型为long double,则另一个应转换为long double
  • 否则,如果任一操作数为double,则另一个应转换为双精度。
  • 否则,如果任一操作数为float,则另一个应转换为float
  • 否则,应在两个操作数上执行积分提升 (4.5)。54
  • 然后,如果任一操作数是unsigned long,另一个应转换为unsigned long
  • 否则,如果一个操作数是long int,另一个是unsigned int,那么如果long int可以表示一个无符号整数的所有值,则无符号整数应转换为long int;否则两个操作数都应转换为无符号long int
  • 否则,如果任一操作数为long,则另一个应转换为long
  • 否则,如果任一操作数为unsigned,则另一个应转换为unsigned

[注意:否则,唯一剩下的情况是两个操作数都是int]


[C++11: 4.5/1]:boolchar16_tchar32_twchar_t 以外的整数类型的纯右值,其整数转换秩(4.13)小于int 的秩可以转换为如果int 可以表示源类型的所有值,则为int 类型的prvalue;否则,可以将源纯右值转换为无符号int 类型的纯右值。

[C++11: 4.5/7]: 这些转化称为整体促销

[C++11: 5.9]: 许多期望算术或枚举类型的操作数的二元运算符会导致转换并以类似的方式产生结果类型。目的是产生一个通用类型,也就是结果的类型。

这种模式称为常用的算术转换,定义如下:

  • 如果任一操作数属于范围枚举类型 (7.2),则不执行任何转换;如果另一个操作数的类型不同,则表达式格式错误。
  • 如果任一操作数为 long double 类型,则另一个应转换为 long double。
  • 否则,如果任一操作数为双精度,则另一个应转换为双精度。
  • 否则,如果任一操作数为浮点数,则另一个应转换为浮点数。
  • 否则,应在两个操作数上执行整数提升 (4.5)。59 然后应将以下规则应用于提升的操作数:
    • 如果两个操作数的类型相同,则无需进一步转换。
    • 否则,如果两个操作数都是有符号整数类型或都具有无符号整数类型,则整数转换等级较小的操作数应转换为等级较高的操作数类型。
    • 否则,如果无符号整数类型的操作数的秩大于或等于另一个操作数类型的秩,则将有符号整数类型的操作数转换为无符号整数类型的操作数的类型。
    • 否则,如果带符号整数类型的操作数的类型可以表示无符号整数类型的操作数类型的所有值,则将无符号整数类型的操作数转换为带符号整数类型的操作数的类型输入。
    • 否则,两个操作数都应转换为与带符号整数类型的操作数类型对应的无符号整数类型。

【讨论】:

  • 哦,等一下……在这两种情况下,此代码的积分促销……哦,呃
  • @LightnessRacesinOrbit,我只是在寻找并想知道是否发生了这种情况。很遗憾,因为那是令人兴奋的学习。
  • 很高兴知道这一点。这值得一个更大、更有针对性、更容易找到的自我回答问题,即轨道中的轻盈竞赛。埋在这里,这个答案很可能会被忽视。
  • @LightnessRacesinOrbit 然后,由于该规则 [C++11: 4.5/1],在进行减法时,两个 uint8_t 都被提升为整数。不知道会发生这种情况:/
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-05-30
  • 2012-04-08
  • 2012-03-17
  • 2023-03-14
  • 2015-12-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多