-9'223'372'036'854'775'808LL не подписано - PullRequest
5 голосов
/ 18 апреля 2020

Поскольку C ++ 20 представление с двумя дополнениями является единственным представлением, разрешенным стандартом, с гарантированным диапазоном от -2 N-1 до + 2 N-1 -1 , Таким образом, для 64-разрядного целого типа со знаком диапазон изменяется от -9'223'372'036'854'775'808 до 9'223'372'036'854'775'807. Тем не менее, этот код не компилируется в Visual Studio (и ни в g cc)

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 будет содержать правильное значение , Что я не получаю здесь?

Ответы [ 3 ]

9 голосов
/ 18 апреля 2020

Без суффикса LL тип берется в качестве первого типа в списке в соответствующем стандарте. Если вы используете суффикс LL, то значение будет иметь тип long long. Однако в любом случае 9'223'372'036'854'775'808 слишком велик, чтобы поместиться в long long (который является самым большим типом со знаком), поэтому некоторые компиляторы допускают, чтобы это расширение стало unsigned long long, что и означает предупреждение. G CC и Clang действительно предупреждают в этом случае . Вопреки мнению многих людей, в C или C ++ нет отрицательного целочисленного литерала. -9'223'372'036'854'775'808 - унарный минус, применяемый к целому числу 9'223'372'036'854'775'808

Тип литерала

Тип целочисленного литерала - первый тип в котором значение может соответствовать, из списка типов, который зависит от того, какая цифра c base и какой целочисленный суффикс .

  • без суффикса
    • десятичные основания:
      • int
      • long int
      • long long int (начиная с C ++ 11)
    • двоичный, восьмеричные или шестнадцатеричные основания:
      • int
      • int без знака
      • long int
      • unsigned long int
      • long long int (начиная с C ++ 11)
      • unsigned long long int (начиная с C ++ 11)
  • ...
  • суффикс: ll или LL
    • десятичные основания:
      • long long int (начиная с C ++ 11)
    • двоичные, восьмеричные или шестнадцатеричные основания
      • long long int
      • unsigned long long int (начиная с C ++ 11)
  • ...

Если значение целочисленного литерала слишком велико, чтобы поместиться в любой из типов, допустимых комбинацией суффикс / основание, и компилятор поддерживает расширенные целочисленные типы (такие как __int128 ) литералу может быть предоставлен расширенный целочисленный тип - в противном случае программа является некорректной.

На самом деле в прошлом было много подобных проблем, где -2147483648 также не подписано, потому что в то время long long не было в стандарте C и C ++ и являлось самым крупным типом is unsigned long:

2 голосов
/ 18 апреля 2020

Это сообщение отвечает на него. Короче говоря, унарный оператор - не является частью целочисленного литерала.

С -9'223'372'036'854'775'807LL - 1 вы начинаете приземляться в пределах long long, устанавливаете его в отрицательное значение, затем вычитаете 1. Другой сразу начинается за пределами.

1 голос
/ 18 апреля 2020

Посмотрим, что здесь происходит. Во-первых, у нас есть целочисленный литерал 9'223'372'036'854'775'808LL. Поскольку это выходит за пределы диапазона для 64-битного числа со знаком, это будет литерал без знака. Теперь примените унарный оператор -. Это не изменит значение этого числа.

(Посмотрите на ту же ситуацию, но на этот раз с 8-битными значениями: 128. Если вы отрицаете это: -128 , он будет иметь тот же битовый шаблон, что и -128, другими словами, значение не меняется.)

И так как 9'223'372'036'854'775'808 не вписывается в long long, сужающее преобразование не может произойти.

...