-9'223'372'036'854'775'808LL 是无符号的

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

因为 C++20 二进制补码表示是标准唯一允许的表示,保证范围从 -2N-1 到 +2 N-1-1。因此,对于 64 位有符号整数类型,范围从 -9'223'372'036'854'775'8089'223'372'036'854'775'807。但是,此代码无法在 Visual Studio 上编译(也不会在 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
}

然而,如果我用 long long x{-9'223'372'036'854'775'807LL - 1} 替换代码编译就好了,x 保持正确的值。我没有得到什么?

回答了它。简而言之,一元 - 运算符不是整数文字的一部分。

使用 -9'223'372'036'854'775'807LL - 1,您开始在 long long 的范围内着陆,将其设置为负数,然后减去 1。另一个立即开始出界。

让我们看看这里发生了什么。首先,我们有一个整数文字 9'223'372'036'854'775'808LL。由于这超出了有符号 64 位数字的范围,因此它将是一个无符号文字。现在,应用一元 - 运算符。 这不会改变这个数字的值。

(看看同样的情况,但这次是 8 位值:128。如果你否定这个:-128,它将具有与 -128 相同的位模式,换句话说,值不变。)

并且由于 9'223'372'036'854'775'808 不适合 long long,因此无法进行缩小转换。

如果没有 LL 后缀,该类型将被视为符合标准的列表中的第一个类型。如果您使用 LL 后缀,那么该值的类型将明确为 long long。然而 无论哪种方式 9'223'372'036'854'775'808 都太大而不适合 long long (这是最大的有符号类型)所以一些编译器允许它作为扩展成为 unsigned long long,因此警告。 GCC 和 Clang do actually warn in that case。与许多人的看法相反,C 或 C++ 中没有负整数文字。 -9'223'372'036'854'775'808 是应用于整数 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.

其实以前有很多类似的issue-2147483648也是unsigned因为当时long long不在C 和 C++ 标准,最大的类型是 unsigned long:

  • Why do we define INT_MIN as -INT_MAX - 1?
  • (-2147483648> 0) returns true in C++?
  • C: Casting minimum 32-bit integer (-2147483648) to float gives positive number (2147483648.0)