Операторы сдвига в C++

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

Кто-то может объяснить меня, что означают вышеупомянутые строки??

10
задан Jon Seigel 10 April 2010 в 18:46
поделиться

6 ответов

Полагаю, вы знаете, что значит переключение передач. Допустим, вы имеете дело с 8-битным char s

unsigned char c;
c >> 9;
c >> 4;
signed char c;
c >> 4;

Первый сдвиг, компилятор может делать все, что захочет, потому что 9> 8 [количество бит в char ]. Неопределенное поведение означает, что все ставки отключены, невозможно узнать, что произойдет. Вторая смена четко обозначена. Слева вы получите 0: 11111111 станет 00001111 . Третий сдвиг, как и первый, не определен.

Обратите внимание, что в этом третьем случае не имеет значения, каково значение c . Когда он ссылается на подписанный , это означает тип переменной, а не то, больше ли фактическое значение нуля. подписанный символ c = 5 и подписанный символ c = -5 оба подписаны, и сдвиг вправо является неопределенным поведением.

5
ответ дан 3 December 2019 в 14:00
поделиться

Если значение после оператора сдвига больше, чем количество бит в левом операнде, результат не определен.

Если вы попытаетесь сдвинуть 32-битное целое число на 33, результат будет неопределенным. то есть, это могут быть нули, а могут и не быть.

Если левый операнд беззнаковый, правый сдвиг является логическим сдвигом, поэтому старшие биты будут заполнены нулями .

Тип данных без знака будет дополнен нулями при сдвиге вправо.

так 1100 >> 1 == 0110

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

Если тип данных подписан, поведение не определено. Типы данных со знаком хранятся в специальном формате, где крайний левый бит указывает положительное или отрицательное значение. Таким образом, переход на целое число со знаком может не дать того, что вы ожидаете. См. Статью в Википедии для подробностей.

http://en.wikipedia.org/wiki/Logical_shift

2
ответ дан 3 December 2019 в 14:00
поделиться

Чтобы дать некоторый контекст, вот начало этого абзаца:

Операторы сдвига также управляют битами. Оператор сдвига влево (<<) создает операнд слева от оператора, сдвинутый влево на количество бит, указанное после оператора. Оператор сдвига вправо (>>) создает операнд слева от оператора, сдвинутый вправо на количество битов, указанное после оператора.

Теперь остальное, с пояснениями:

Если значение после оператора сдвига больше, чем количество бит в левом операнде, результат не определен.

Если у вас есть 32-битное целое число и вы пытаетесь сдвинуть бит на 33 бита, это недопустимо, и результат не определен. Другими словами, результатом может быть что угодно, или ваша программа может вылететь.

Если левый операнд беззнаковый, сдвиг вправо является логическим сдвигом, поэтому старшие биты будут заполнены нулями.

Это говорит о том, что определена запись a >> b , когда a - беззнаковое целое число. При сдвиге вправо наименее значимые биты удаляются, другие биты сдвигаются вниз, а наиболее значимые биты становятся нулевыми.

Другими словами:

This:    110101000101010 >> 1
becomes: 011010100010101

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

На самом деле я считаю, что поведение здесь определяется реализацией, когда a отрицательно, и определяется, когда a положительно, а не неопределенным, как предлагается в цитате. Это означает, что если вы выполните a >> b , когда a является отрицательным целым числом, может произойти много разных вещей. Чтобы узнать, что у вас получится, вам следует прочитать документацию к вашему компилятору. Распространенной реализацией является сдвиг нулей, если число положительное, и единиц, если число отрицательное, но вы не должны полагаться на это поведение, если хотите писать переносимый код.

2
ответ дан 3 December 2019 в 14:00
поделиться

Я полагаю, что ключевое слово - «undefined», что означает, что в спецификации не сказано, что должно произойти. Большинство компиляторов сделают что-нибудь разумное в таких случаях, но вы не можете вообще зависеть от какого-либо поведения. Обычно лучше избегать вызова неопределенного поведения, если в документации к компилятору, который вы используете, не указано, что он делает в конкретном случае.

В первом предложении говорится, что оно не определено, если вы попытаетесь сдвинуть, например, 32-битное значение более чем на 32 бита.

Второй говорит, что если вы сдвинете беззнаковое int вправо, левые биты будут заполнены нулями.

Третий говорит, что если вы сдвинете знаковое int вправо, не определено, что будет помещено в левые биты.

1
ответ дан 3 December 2019 в 14:00
поделиться

Если значение после оператора сдвига больше, чем количество бит в левом операнде, результат не определен.

Это означает, что (unsigned int) x >> 33 может делать что угодно [1].

Если левый операнд беззнаковый, сдвиг вправо является логическим сдвигом, поэтому старшие биты будут заполнены нулями.

Это означает, что 0xFFFFFFFFu >> 4 должно быть 0x0FFFFFFFu

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

Это означает, что 0xFFFFFFFF >> 4 может быть 0xFFFFFFFF (арифметический сдвиг) или 0x0FFFFFFF (логический сдвиг) или любым другим, разрешенным физическим законом , т.е. результат не определен.

[1]: на 32-битной машине с 32-битным int .

5
ответ дан 3 December 2019 в 14:00
поделиться

Неважно, что означают эти строки, они по существу неверны.

«Если значение после оператора сдвига больше, чем количество битов в левом операнде, результат будет не определен».

Is Верно, но должно быть указано "больше или равно". 5.8 / 1:

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

Неопределенное поведение означает «не делай этого» (см. Ниже). То есть, если int в вашей системе 32 бита, то вы не можете допустимо выполнить любое из следующего:

int a = 0; // this is OK
a >> 32;   // undefined behavior
a >> -1;   // UB
a << 32;   // UB
a = (0 << 32); // Either UB, or possibly an ill-formed program. I'm not sure.

«Если левый операнд беззнаковый, сдвиг вправо является логическим сдвигом. так что верхние биты будут заполнены нулями »

Это правда. 5.8 / 3 говорит:

Если E1 имеет беззнаковый тип или если E1 имеет подписанный тип и неотрицательное значение, результат является неотъемлемой частью частного от E1 делится на количество 2, возведенное в степень E2

, если это имеет для вас больше смысла. >> 1 аналогично делению на 2, >> 2 делению на 4, >> 3 на 8 и т. Д. В двоичном представлении положительного значения деление на 2 аналогично перемещению всех битов на один вправо, отбрасыванию самого маленького бита и заполнению самого большого бита нулем.

"Если левый операнд равен подписано, сдвиг вправо может быть или не быть логическим сдвигом (то есть поведение не определено) ».

Первая часть верна (это может быть или не быть логическим сдвигом - это есть на некоторых компиляторах / платформах, но не другие. Я думаю, что наиболее распространенным поведением является то, что это не так). Вторая часть неверна, поведение не определено. Неопределенное поведение означает, что может произойти все, что угодно - авария, вылетающие из носа демоны, случайное значение, что угодно. Стандарт не заботится. Существует множество случаев, когда стандарт C ++ говорит, что поведение не определено, но это не один из них.

Фактически, если левый операнд подписан и значение положительное, то он ведет себя так же, как беззнаковый сдвиг.

Если левый операнд подписан и значение отрицательное, то результирующее значение определяется реализацией. Запрещается разбиться или загореться. Реализация должна давать результат, и документация по реализации должна содержать достаточно информации, чтобы определить, каким будет результат. На практике «документация по реализации» начинается с документации компилятора, но она может неявно или явно отсылать вас к другим документам для ОС и / или ЦП.

Опять же из стандарта, 5.8/3:

Если E1 имеет тип со знаком и отрицательное значение , результирующее значение определяется реализацией.

23
ответ дан 3 December 2019 в 14:00
поделиться
Другие вопросы по тегам:

Похожие вопросы: