c++integerliteralsc++20long-long

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


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?


Solution

  • 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: