-9'223'372'036'854'775'808LL is unsigned

时间秒杀一切 提交于 2021-02-04 05:56:50

问题


Since C++20 two's complement representation is the only representation allowed by the standard, with the guaranteed range from -2N-1 to +2N-1-1. So for a 64-bit signed integer type the range goes from -9'223'372'036'854'775'808 to 9'223'372'036'854'775'807. However, this code does not compile on Visual Studio (and neither on gcc)

int main()
{
    long long x{-9'223'372'036'854'775'808LL};
    // error C4146: unary minus operator applied to unsigned type, result still unsigned
    // error C2397: conversion from 'unsigned __int64' to '__int64' requires a narrowing conversion
}

Yet, if I replace the code with long long x{-9'223'372'036'854'775'807LL - 1} compiles just fine and x holds the correct value. What am I not getting here?


回答1:


Without the LL suffix the type is taken as the first type in the list in the standard that fits. If you use the LL suffix then the value will specifically have type long long. However either way 9'223'372'036'854'775'808 is too large to fit in a long long (which is the largest signed type) so some compilers allow it as an extension to become unsigned long long, hence the warning. GCC and Clang do actually warn in that case. Contrary to many people's belief, there's no negative integer literal in C or C++. -9'223'372'036'854'775'808 is a unary minus applying to the integer 9'223'372'036'854'775'808

The type of the literal

The type of the integer literal is the first type in which the value can fit, from the list of types which depends on which numeric base and which integer-suffix was used.

  • no suffix
  • decimal bases:
    • int
    • long int
    • long long int (since C++11)
  • binary, octal, or hexadecimal bases:
    • int
    • unsigned int
    • long int
    • unsigned long int
    • long long int (since C++11)
    • unsigned long long int (since C++11)
  • ...
  • suffix: ll or LL
  • decimal bases:
    • long long int (since C++11)
  • binary, octal, or hexadecimal bases
    • long long int
    • unsigned long long int (since C++11)
  • ...

If the value of the integer literal is too big to fit in any of the types allowed by suffix/base combination and the compiler supports extended integer types (such as __int128) the literal may be given the extended integer type -- otherwise the program is ill-formed.

In fact there are a lot of similar issues in the past where -2147483648 is also unsigned because at that time long long wasn't in the C and C++ standards and the largest type is unsigned long:

  • Why do we define INT_MIN as -INT_MAX - 1?
  • (-2147483648> 0) returns true in C++?
  • Why does the smallest int, −2147483648, have type 'long'?
  • Why is 0 < -0x80000000?
  • Why does MSVC pick a long long as the type for -2147483648?
  • C: Casting minimum 32-bit integer (-2147483648) to float gives positive number (2147483648.0)



回答2:


This post answers it. In short, unary - operator is not part of integer literal.

With -9'223'372'036'854'775'807LL - 1 you start off landing within the confines of long long, set it to negative, then subtract 1. The other immediatelly starts outside of bounds.




回答3:


Let's see what happens here. First, we have an integer literal of 9'223'372'036'854'775'808LL. As this is out of range for a signed 64-bit number, it will be an unsigned literal. Now, apply the unary - operator. This won't change the value of this number.

(Have a look at the same situation, but this time with 8-bit values: 128. If you negate this: -128, it will have the same bit-pattern as -128, in other words, the value doesn't change.)

And as 9'223'372'036'854'775'808 doesn't fit into long long, narrowing conversion cannot happen.



来源:https://stackoverflow.com/questions/61290255/9223372036854775808ll-is-unsigned

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!