Сменные операции - PullRequest
       17

Сменные операции

0 голосов
/ 23 февраля 2009

Я видел следующее, опубликованное одним из собратьев по стеку, и это меня как-то ошарашило.

Может ли кто-нибудь объяснить операции сдвига в следующем фрагменте кода:

std::vector<bool> a;
a.push_back(true);
a.push_back(false);
//...
for (auto it = a.begin(); it != a.end();) // see 0x for meaning of auto
{
    unsigned b = 0;
    for (int i = 0; i < 8*sizeof(b); ++i)
    {
        b |= (*it & 1) << (8*sizeof(b) - 1 - i);
        ++it;
    }
    // flush 'b'
}

Ответы [ 3 ]

3 голосов
/ 23 февраля 2009

8 * sizeof (b) - это количество битов, которые могут быть сохранены в 'b' (это целое число без знака, то есть обычно 32 или 64 бита).

Что делает код, так это упаковывает логические значения в векторе 'a', чтобы они стали битами в 'b'.

"* it & 1" обнуляется до 1, если логическое значение в * это ИСТИНА, в противном случае 0. Затем бит сдвигается влево на 32 бита минус 1 минус индекс 'i', то есть сдвигается влево от нуля до 31 бита , Теперь это означает, что первый элемент «a» будет управлять старшим значащим битом в «b» (левый сдвиг 31), второй элемент - вторым старшим значащим битом в «b» (левый сдвиг 30) и т. Д. Обратите внимание, что в C сдвиги являются арифметическими, т.е. независимо от байтов или порядка битов, x << 1 всегда равно x * 2. </p>

Так, например, если в вашем векторе заданы первый и 30-й элементы, к концу дня b должно содержать двоичное число 10000000 00000000 00000000 00000100.

0 голосов
/ 23 февраля 2009

Что там происходит:

(*it & 1)

это должно быть 0 или 1 в зависимости от того, является ли bool истинным или ложным; заметьте, однако, что bools всегда 0 или 1, так что это может быть (без знака) * it

<< (8*sizeof(b) - 1 - i)

Это сдвиг, который перемещает бит из крайнего правого положения в i -й слева. Мы сдвигаем число, для которого установлен не более одного бита, поэтому для него будет установлен i -й крайний левый бит или нет. Остальные биты равны нулю.

b |= ...

это устанавливает те биты в b, которые включены в RHS.

i++;

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

Это означает, что все будет устанавливать биты в b, соответствующие векторным элементам, которые являются истинными.

0 голосов
/ 23 февраля 2009

Ответ antti.huima мне подходит.

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

если вы передадите вектор с «нечетным» размером, скажем, 33 записи, результат может быть неверным.

Это не может быть ошибкой, если размер вектора гарантирован (но, возможно, следует проверить правильность длины).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...