Смущен неопределенным поведением оператора сдвига в C ++ и переносом «пространства образца»

Я смущен тем, что я прочитал в разделе «Операторы сдвига» статья о неопределенном поведении 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 биты. Предупреждение это хорошо, так как это, вероятно, было ошибкой, но я не вижу неопределенного поведения …

2

Решение

Если вы используете машинные инструкции x86 или x64 для сдвига значения, они маскируют величину сдвига и используют только младшие биты для фактического сдвига. Некоторые другие устройства могут этого не делать.

Вот почему это не определено.

В вашем примере с литералами 1 << 32вполне вероятно, что компилятор вычисляет значение, и поэтому 0, Попробовав работу на реальном оборудовании x86, вы получите 1,

4

Другие решения

Тип результата — тип повышенного левого операнда. Поведение не определено, если правый операнд отрицательный, или больше или равен длине в битах повышенного левого операнда.

Это из §5.8 / 1 из C ++ 11. Если ваши целые 32-битные, вы не можете сдвинуться на 32 (вправо или влево, независимо от подписи левого операнда).

3

Согласно спецификации C ++, если вы сдвигаете 32-битное значение влево на 32, результат всегда равен 0

Нет, это не то, что говорит стандарт. Поведение 32-битного типа на 32 или более не определено (5.8 / 1)

Так как при ARM сдвиг на 256 битов (который не имеет типа 257-бит или более) является неопределенным поведением, CPU в этот момент имеет полное право на перенос.

3
По вопросам рекламы [email protected]