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

Приведенный выше код будет получить следующее сообщение об ошибке:Почему я не могу использовать '0x80000000' для инициализации массива int?

error: narrowing conversion of ‘2147483648u’ from ‘unsigned int’ to ‘int’ inside { } [-Wnarrowing] int arr[1] = {0x80000000};

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

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

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

+2

Вы можете, просто не из 32-ти, а типа (какой 'int' кажется на вашей машине). – StoryTeller

+0

'[1]' - красная селедка, вы получите такое же поведение с простым 'int' –

ответ

7

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

list-initialization limits the allowed implicit conversions by prohibiting the following:

  • ...
  • conversion from integer or unscoped enumeration type to integer type that cannot represent all values of the original, except where source is a constant expression whose value can be stored exactly in the target type

И о поведении неявного преобразования, т.е. integral conversions в назначении:

If the destination type is signed, the value does not change if the source integer can be represented in the destination type. Otherwise the result is implementation-defined.

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

+0

Re. последний абзац: это называется преобразованием вне диапазона, а не * переполнением * (что и происходит, когда арифметическая операция приведет к выходу за пределы диапазона) –

1

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

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

+2

Просто для nitpick. Компилятор выполняет * преобразования *, некоторые неявные и некоторые явные. Программист задает такое явное преобразование посредством * casting *. – StoryTeller

+1

Вы не отметили важный момент, что это * преобразование * (не выполняется) не происходит с C++ 11, код плохо сформирован. Однако это не связано с «отображением непосредственно массива в память» (что бы это ни подразумевало). Этот код был законным в C++ 03 (с поведением, определяемым реализацией, как вы объясните). Изменение в C++ 11 было сделано с целью помочь программистам избежать написания ошибок, а не технических ограничений. –

2

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

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

 Смежные вопросы

  • Нет связанных вопросов^_^