为什么int加上uint会返回uint?

13

int加上unsigned int返回一个unsigned int。这样做合理吗?

考虑以下代码:

#include <boost/static_assert.hpp>
#include <boost/typeof/typeof.hpp>
#include <boost/type_traits/is_same.hpp>

class test
{
    static const int          si = 0;
    static const unsigned int ui = 0;

    typedef BOOST_TYPEOF(si + ui) type;
    BOOST_STATIC_ASSERT( ( boost::is_same<type, int>::value ) ); // fails
};


int main()
{
    return 0;
}

1
也许你应该问那些设计这种语言的人。 - Mysticial
网站上有另一篇关于同一主题的帖子,您可以在这里找到:https://dev59.com/hXI95IYBdhLWcg3w8iv1 希望这能帮到您! - lkaradashkov
+1 表示提供完整的测试用例。http://sscce.org - Robᵩ
3个回答

17
如果你说“应该是”的意思是“我的编译器是否按照标准行事”,那么是的
C++2003:第5条第9款:
许多期望算术或枚举类型操作数的二元运算符会引起转换并以类似的方式产生结果类型。其目的是产生一个常见类型,这也是结果的类型。这种模式称为通常算术转换,其定义如下:
  • blah
  • 否则,blah
  • 否则,blah,...
  • 否则,如果任一操作数为无符号,则另一个应转换为无符号。
如果您说“应该是”的意思是“如果没有它,世界会变得更好吗”:我不够称职回答这个问题。

我相信C++标准委员会的目标是让世界变得更美好,所以当我说“应该这样做”时,实际上是指“如果不这样做,世界将不会变得更美好”。 - Vahagn
1
@Vahagn - 那么(int)0x70000000 + (unsigned int)0x70000000的结果将为正值。 - Robᵩ

2
无符号整数类型的行为大多表现为一个环绕的抽象代数值环的成员,其值在模2^N下等效;可以将一个N位无符号整数视为不表示特定整数,而是具有底部N位中特定值的所有整数集合。例如,如果将两个二进制数的最后4位分别为...1001...0101相加,则结果将为...1110。如果将...1111...0001相加,则结果将为...0000;如果从...0000中减去...0001,则结果将为...1111。请注意,溢出或下溢的概念并没有真正意义,因为操作数的上位值是未知的,结果的上位值也不重要。还要注意,将已知上位位的有符号整数与“未知/不关心”上位位的整数相加应产生一个上位位为“未知/不关心”的数字(这就是无符号整数类型的主要行为)。
唯一无法像环绕代数环的成员那样运作的地方是当它们参与比较、用于数值除法(这意味着比较),或提升为其他类型时。如果将无符号整数类型转换为更大的类型的唯一方法是使用操作符或函数,那么使用这样的操作符或函数可以清楚地表明它正在做出关于上位位的假设(例如,将“某些底部位为...00010110”的数字转换为“底部位为...00010110且所有上位位都为零的数字)。不幸的是,C语言并没有这样做。将一个与大小相等的有符号值加到无符号值上会产生一个相同大小的无符号值(这与上面对无符号值的解释是有意义的),但将一个较大的有符号整数加到无符号类型中会导致编译器默默地假定后者的所有上位位都是零。在某些编译器的提升规则下,此行为可能特别令人恼火,因为有些编译器可能认为两个表达式具有相同的大小,而其他编译器可能将它们视为不同的大小。

Downvoter: 有什么评论吗?无符号整数类型通常用于有效地计算较大值的低位并忽略其上位(例如,使用uint8_t值来累加一堆字节的总和)。我的描述与正常描述不符,但它与这种用法一致,并代表了大多数程序员的意图,这依赖于无符号整数包装行为;它也与编译器生成的代码一致,例如uint16_t x,y,z; ... x = y * z;在计算y*z之后,需要忽略结果中除了低16位以外的所有位。 - supercat

1
很可能这种行为源于指针类型的逻辑(内存位置,例如std::size_t),加上内存位置差异(std::ptrdiff_t)也是一个内存位置。

换句话说,std::size_t = std::size_t + std::ptrdiff_t

当这种逻辑被转化为底层类型时,意味着unsigned long = unsigned long + long,或者unsigned = unsigned + int

@supercat提出的“其他”解释也可能是正确的。

显然,无符号整数并不是设计成或不应被解释为数学正数,即使在原则上也不是。请参见https://www.youtube.com/watch?v=wvtFGa6XJDU


size_tptrdiff_t比C类型提升规则要新很多。 - Michel de Ruiter
@MicheldeRuiter,不同于什么?它们是某些底层内置类型的typedef,这些类型将遵循C语言提升规则。我只是在说它们以类似的方式一致地表现。 - alfC
行为怎么可能来源于不存在的东西?这根本没有回答问题。但是链接很有价值! - Michel de Ruiter
@MicheldeRuiter,unsigned和地址之间的类比以及signed作为偏移量的存在早在C++之前就已经存在了,这就是我想要指出的。 (由于这是一个C++问题,因此提到标准类型是可以的。) - alfC

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接