CSAPP: что должно произойти, если я хочу сдвинуть 8-битное число на 8 позиций влево - PullRequest
2 голосов
/ 13 апреля 2020

Этот вопрос из CSAPP CMU ICS 2015Fall Lecture 02 Биты, байты и целые числа 19: 30 и связанные сценарии

Другой люди смущают:

Что должно произойти, если вы скажете, что я хочу сдвинуть 8-битное число на 8 позиций влево

И x - это один байт, что, как вы думаете, следует делать получить

ноль, что было бы довольно логично, если бы вы сместили все эти биты, заполнив их нулями

----------- Я не понимаю -----------

На большинстве машин вы получите то, что было х

Потому что, что будет делать, он вычислит это число мод 8

И причина, по которой это происходит, если вы думаете об этом

Он смотрит только на младшие два три бита величины сдвига и игнорирует все остальные

Так что это по сути похоже на модуль 8

Так что это всего лишь предупреждение, и некоторые машины это делают

То, что вы только что подумали, и другое на машинах он делает это

И поэтому нет никакой гарантии, и в C, что это будет так или иначе

Рэндал Брайант говорит, что есть два результата, когда сдвиг 8-битного числа на 8 позиций влево. (Поправьте меня, если я ошибаюсь)

  1. ноль
  2. модуль 8 без изменений

Я помещаю горизонтальное правило для разделения часть, которую я не понимаю. Особенно На большинстве машин вы получите то, что было х было и . Потому что он будет вычислять этот числовой мод 8 , я не понимаю, почему х то же самое с модом х 8.

Может ли кто-нибудь объяснить немного больше в части ниже горизонтального правила, лучше с работающей программой?

Есть несколько связанных вопросов по SO, например Что происходит с побитовым сдвигом для всех 8 битов и Операция сдвига влево для 8-разрядного целого числа без знака , но оба не содержали модульную часть.

1 Ответ

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

Сдвиг 8-разрядного байта на 8 позиций влево можно анализировать различными способами:

  • Арифметически, сдвиг значения на 8 позиций влево - это умножение на 256, что дает число чьи 8 младших битов равны нулю, поэтому при сохранении обратно в 8-битный байт вы получите 0.
  • Команда аппаратного сдвига, как правило, только сдвигает слова памяти на количество битов, которое меньше их ширина. На многих архитектурах, таких как Intel, этот номер величины сдвига получается путем маскировки битов старшего порядка значения сдвига. Таким образом, инструкция смещения байта на 8 позиций влево эффективно смещает значение в 8-битном регистре или аргументе памяти на 8 & 7 позиций, то есть на 0 бит, оставляя значение без изменений.
  • Для размещения из-за аппаратных ограничений язык C делает неопределенным смещение целого числа на количество позиций, большее или равное его ширине. Это применяется после целочисленных преобразований , поэтому оно не применяется к 8-разрядным байтам (например, хранящимся в uint8_t), поскольку эти значения сначала повышаются до типа int, который имеет по крайней мере 15 битов значения.

Таким образом, в языке C смещение байта на 8 позиций умножает его значение на 256, что может в конечном итоге превысить диапазон типа int в архитектурах с 16-битным ints.

Давайте проанализируем этот невинно выглядящий код:

    uint8_t shift8(uint_8 b) {
        return b << 8;
    }

Поскольку b сначала переводится в int, сохраняя его значение. Это значение умножается на 256, потенциально превышая диапазон int, вызывая неопределенное поведение. На архитектурах с int больше 16 битов значение затем неявно преобразуется в тип возврата uint8_t, который полностью определяется и оценивается в значение по модулю 256, которое, конечно, равно 0.

Так что Вышеуказанная функция является конформной и всегда возвращает 0 во многих системах, но она не полностью совместима и имеет неопределенное поведение в архитектурах с 16-битными целыми числами.

...