Why does int plus uint return uint?

int plus unsigned int returns unsigned int. Should it be like that?

Consider this code:

#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; } 
+8
source share
3 answers

If “should it be,” you mean “my compiler behaves according to the standard”: yes .

C ++ 2003: Clause 5, Clause 9:

Many binary operators expecting operands of arithmetic or an enumeration type cause conversions and profitability in a similar way. The goal is to give a generic type, which is also a result type. This pattern is called regular arithmetic conversions, which are defined as follows:

  • l
  • Otherwise, blah,
  • Other, blah ...
  • Otherwise, if any unsigned operand, the other must be converted to unsigned.

If “should it be,” you mean “the world would be a better place if it weren’t”: I am not competent to answer that.

+12
source

Unsigned integer types basically behave as members of a wrapping abstract algebraic ring of values ​​that are equivalent to mod 2 ^ N; one could see an unsigned N-bit integer not representing a specific integer, but the set of all integers with a specific value in the lower N bits. For example, if you add two binary numbers, the last 4 digits of which are ...1001 and ...0101 , the result will be ...1110 . If you add ...1111 and ...0001 , the result will be ...0000 ; if you subtract ...0001 from ...0000 , the result is ...1111 . Please note that the concepts of overflow or lower stream do not really mean anything, since the upper bit values ​​of the operands are unknown, and the values ​​of the upper bit of the result are not of interest. Also note that adding a signed integer whose upper bits are known to one whose upper bits are “don't know / don't care” should give a number whose upper bits are “don't know / don't care” (which is that unsigned integer types in basically behave like).

The only places where unsigned integer types cannot behave as members of a wrapping algebraic ring are when they participate in comparisons, are used in numerical division (which implies comparison), or apply to other types. If the only way to convert an unsigned integer type to something more was to use an operator or function for this purpose, using such an operator or function could make it clear that it makes assumptions about the upper bits (for example, by turning "some number" whose lower-order bits ...00010110 "in" is a number whose lower bits are ...00010110 , and the upper bits are all zeros). Unfortunately, C does not. Adding a sign in an unsigned value of equal size gives (which makes sense when interpreting unsigned values ​​above), but adding a larger significant integer to an unsigned type will make the compiler silently assume that all the upper bits of the latter are zero. This behavior can be especially annoying when, depending on the rules for promoting compilers, some compilers may consider two expressions to be the same, while others may treat them as different sizes.

0
source

It is likely that the behavior stems from the logic underlying the pointer types (memory location, for example std::size_t ), and also the difference in memory location ( std::ptrdiff_t ) is also a memory cell.

In other words, std::size_t = std::size_t + std::ptrdiff_t .

When this logic is translated to type litter, it means unsigned long = unsigned long + long or unsigned = unsigned + int .

The "other" explanation from @supercat is also possibly correct.

0
source

All Articles