Я смущен тем, что я прочитал в разделе «Операторы сдвига» статья о неопределенном поведении C ++.
В архитектуре ARM операторы сдвига всегда ведут себя так, как если бы они имели место в 256-битном пространстве шаблона, независимо от размера операнда, то есть шаблон повторяется или «оборачивается» только через каждые 256 позиций. Другой способ думать об этом состоит в том, что шаблон смещается на указанное число позиций по модулю 256. Тогда, конечно, результат содержит только самые младшие биты пространства шаблона.
Таблицы особенно странные:
Given a 32-bit integer with a value of 1:
+-----------------------------------+
| Shift left ARM x86 x64 |
+-----------------------------------+
| 32 0 1 1 |
| 48 0 32768 32768 |
| 64 0 1 1 |
+-----------------------------------+
Каковы эти ценности, и почему они имеют значение?
операторы сдвига не оборачивайся Согласно спецификации C ++, если вы сдвигаете 32-битное значение влево на 32, результат всегда равен 0. (РЕДАКТИРОВАТЬ: я не прав, см. Ответы!) Так к чему эта статья? Что такое неопределенное поведение?
Когда я запускаю этот код на x86, я получаю 0
:
printf("%d", 1 << 32);
предположительно этот фрагмент кода иллюстрирует проблему:
// C4293.cpp
// compile with: /c /W1
unsigned __int64 combine (unsigned lo, unsigned hi) {
return (hi << 32) | lo; // C4293
// try the following line instead
// return ( (unsigned __int64)hi << 32) | lo;
}
Я ожидаю, что возвращаемое значение будет lo
, так как программист убрал все hi
биты. Предупреждение это хорошо, так как это, вероятно, было ошибкой, но я не вижу неопределенного поведения …
Если вы используете машинные инструкции x86 или x64 для сдвига значения, они маскируют величину сдвига и используют только младшие биты для фактического сдвига. Некоторые другие устройства могут этого не делать.
Вот почему это не определено.
В вашем примере с литералами 1 << 32
вполне вероятно, что компилятор вычисляет значение, и поэтому 0
, Попробовав работу на реальном оборудовании x86, вы получите 1
,
Тип результата — тип повышенного левого операнда. Поведение не определено, если правый операнд отрицательный, или больше или равен длине в битах повышенного левого операнда.
Это из §5.8 / 1 из C ++ 11. Если ваши целые 32-битные, вы не можете сдвинуться на 32 (вправо или влево, независимо от подписи левого операнда).
Согласно спецификации C ++, если вы сдвигаете 32-битное значение влево на 32, результат всегда равен 0
Нет, это не то, что говорит стандарт. Поведение 32-битного типа на 32 или более не определено (5.8 / 1)
Так как при ARM сдвиг на 256 битов (который не имеет типа 257-бит или более) является неопределенным поведением, CPU в этот момент имеет полное право на перенос.