Какая причина, по которой языки высокого уровня, такие как С#/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 компилятор может просто использовать инструкцию переключения аппаратного обеспечения и делать все, что он делает.