Какая причина, по которой языки высокого уровня, такие как С#/Java, маскируют операнд счетчика сдвига бит?

Это скорее языковой дизайн, чем вопрос программирования.

Ниже приведен фрагмент JLS 15.19 Операторы сдвига:

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

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

Это поведение также указанное в С#, и пока я не уверен, что это в официальной спецификации для Javascript (если есть), это также верно, основываясь на моем собственном тесте, по крайней мере.

Следствием этого является то, что верно следующее:

(1 << 32) == 1

Я понимаю, что эта спецификация, вероятно, "вдохновлена" тем фактом, что базовое оборудование принимает только 5 бит для операнда count при смещении 32-битных значений (и 6 бит для 64-разрядных), и я могу понять такое поведение например, на уровне JVM, но почему языки высокого уровня, такие как С# и Java, сохраняют это поведение на довольно низком уровне? Разве они не должны предоставлять более абстрактный вид за пределы аппаратной реализации и вести себя более интуитивно? (Еще лучше, если они могут принять отрицательное значение, чтобы означать смещение в направлении OTHER!)

Ответ 1

Java и С# не полностью "высокоуровневые". Они очень стараются быть такими, чтобы их можно было скомпилировать в эффективный код, чтобы сиять в микро-тестах. Вот почему они имеют "типы значений", такие как int, вместо того, чтобы иметь в качестве целочисленного типа по умолчанию целые значения true, которые будут объектами по своему усмотрению и не ограничиваются фиксированным диапазоном.

Следовательно, они имитируют то, что делает оборудование. Они немного подстраиваются, поскольку они маскируют маски, тогда как C разрешает это. Тем не менее, Java и С# являются "средними" языками.

Ответ 2

Так как в большинстве программных сред целое число составляет всего 32 бита. Таким образом, 5 бит (что достаточно, чтобы выразить 32 значения) уже достаточно, чтобы сдвинуть целое целое число. Аналогичная аргументация существует для 64-битной длины: 6 бит - это все, что вам нужно, чтобы полностью сдвинуть все значение.

Я могу понять часть путаницы: если ваш правый операнд является результатом вычисления, которое заканчивается значением больше 32, вы можете ожидать, что он просто сдвинет все биты, а не применит маску.

Ответ 3

С# и Java определяют сдвиг, поскольку используют только младшие разряды счетчика сдвига, как это делают обе команды сдвига и x86. Java первоначально была реализована Sun на процессорах sparc и С# от Microsoft на x86.

В отличие от этого, C/С++ оставляет в качестве undefined поведение команд сдвига, если количество сдвигов не находится в диапазоне 0..31 (для 32-битного int), что позволяет любое поведение. Это потому, что, когда C был впервые реализован, разные прикладные программы обрабатывали их по-разному. Например, на VAX смещение на отрицательную величину сдвигает другое направление. Таким образом, с помощью C компилятор может просто использовать инструкцию переключения аппаратного обеспечения и делать все, что он делает.