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