#include<iostream>
int main()
{
    int arr[1] = {0x80000000};
    std::cout<<arr[0]<<"\n";
    return 0;
}

Приведенный выше код приведет к следующей ошибке:

ошибка: сужение преобразования «2147483648u» из «unsigned int» в «int» внутри {} [-Wnarrowing] int arr [1] = {0x80000000};

Но следующий код работает отлично:

#include<iostream>    
int main()
{
    int arr[1];
    arr[0] = 0x80000000;
    std::cout<<arr[0]<<"\n";
    return 0;
}

Итак, мой вопрос: почему я не могу использовать «0x80000000» для инициализации массива int?

-1
Ren 4 Сен 2016 в 15:22

3 ответа

Лучший ответ

0x80000000 здесь не помещается int, поэтому это целочисленный литерал с типом unsigned int. Для инициализации требуется неявное преобразование, но кроме присваивания, неявные преобразования ограничены, т. Е. Сужающие преобразования запрещены в инициализация списка (начиная с C ++ 11):

list-initialization ограничивает разрешенные неявные преобразования, запрещая следующее:

  • ...
  • преобразование из целочисленного типа перечисления или типа перечисления без области действия в целочисленный тип, который не может представлять все значения оригинала, за исключением случаев, когда источник является константным выражением, значение которого может быть сохранено точно в целевом типе

И о поведении неявного преобразования, то есть интегральных преобразований в присваивании :

Если тип назначения подписан, значение не изменяется, если целое число источника может быть представлено в типе назначения. В противном случае результат определяется реализацией.

Поведение преобразования вне диапазона определяется реализацией, например он может оборачиваться согласно правилам представления (обычно до 2).

7
songyuanyao 4 Сен 2016 в 13:09

Он не «работает идеально». Он может компилироваться , когда вы используете конструкцию, которая позволяет выполнять усечение без уведомления, но это не означает, что усечения не происходит. Вы все равно получите неправильный результат, поскольку ваше значение не помещается в signed int, компилятор просто не поможет вам обнаружить вашу ошибку в этом случае.

Помнить; "компилирует"! = "работает".

2
Jesper Juhl 4 Сен 2016 в 12:35

Потому что здесь arr[0] = 0x80000000; компилятор выполняет приведение (здесь мы говорим int = 32 бита), которое определяется реализацией (в зависимости от компилятора). Вы также можете получить предупреждения на некоторых компиляторах.

Но компилятор не может выполнить приведение при инициализации, потому что он напрямую отображает массив в память.

1
Jean-François Fabre 4 Сен 2016 в 12:27