Являются операторы сдвига (<<>>) арифметикой или логичный в C?

В C, операторы сдвига (<<, >>) арифметика или логичный?

120
задан Ciro Santilli 新疆改造中心法轮功六四事件 9 August 2016 в 16:02
поделиться

6 ответов

Согласно K& R 2-й выпуск результаты являются зависящими от реализации для сдвигов вправо значений со знаком.

Википедия говорит, что C/C++ 'обычно' реализует арифметический сдвиг на значениях со знаком.

В основном необходимо или протестировать компилятор или не полагаться на него. Моя справка VS2008 для текущего компилятора C++ MS говорит, что их компилятор делает арифметический сдвиг.

91
ответ дан Bulat M. 24 November 2019 в 01:36
поделиться

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

(Как фон для тех читателей, незнакомых с различием, "логический" сдвиг вправо 1 сдвигом разряда все биты направо и заполняет крайний левый бит с 0. "Арифметический" сдвиг оставляет исходное значение в крайнем левом бите. Различие становится важным при контакте с отрицательными числами.)

При смещении неподписанного значения,>> оператор в C является логическим сдвигом. При смещении значения со знаком>> оператор является арифметическим сдвигом.

, Например, принимая машину на 32 бита:

signed int x1 = 5;
assert((x1 >> 1) == 2);
signed int x2 = -5;
assert((x2 >> 1) == -3);
unsigned int x3 = (unsigned int)-5;
assert((x3 >> 1) == 0x7FFFFFFD);
126
ответ дан Greg Hewgill 24 November 2019 в 01:36
поделиться

С точки зрения типа сдвига Вы добираетесь, важной вещью является тип значения, которое Вы смещаете. Классический источник ошибок - при смещении литерала к, скажем, нулевым разрядам маски. Например, если бы Вы хотели отбросить крайний левый бит целого числа без знака, тогда Вы могли бы попробовать это как свою маску:

~0 >> 1

, К сожалению, это получит Вас в проблему, потому что маска будет иметь весь свой набор битов, потому что значение, смещаемое (~0), подписывается, таким образом арифметический сдвиг выполняется. Вместо этого Вы хотели бы вызвать логический сдвиг путем явного объявления значения как неподписанного, т.е. путем выполнения чего-то вроде этого:

~0U >> 1;
16
ответ дан Nick 24 November 2019 в 01:36
поделиться

Ну, я смотрел это на Википедию , и они говорят следующее:

C, однако, имеет только один оператор сдвига вправо,>>. Много компиляторов C выбирают, какой сдвиг вправо выполнить в зависимости от того, какое целое число смещается; часто целые числа со знаком смещаются с помощью арифметического сдвига, и целые числа без знака смещаются с помощью логического сдвига.

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

4
ответ дан Mike Stone 24 November 2019 в 01:36
поделиться

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

будет использовать это, когда применимо, как другие компиляторы, вероятно, сделают.

0
ответ дан LPs 24 November 2019 в 01:36
поделиться

Вот функции, гарантирующие логический сдвиг вправо и арифметический сдвиг вправо для int в C:

int logicalRightShift(int x, int n) {
    return (unsigned)x >> n;
}
int arithmeticRightShift(int x, int n) {
    if (x < 0 && n > 0)
        return x >> n | ~(~0U >> n);
    else
        return x >> n;
}
16
ответ дан 24 November 2019 в 01:36
поделиться
Другие вопросы по тегам:

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