2015-09-08 6 views
7

Я не изучал ИТ, и только совсем недавно наткнулся на bit shifts и приложение для two's complement. Итак, можете ли вы использовать простой английский в своих объяснениях и предположить, что я почти ничего не знаю о IP-адресах, битовых операциях и типах данных Java?Как работает оператор сдвига в Java под капотом?

Сегодня я нашел следующий фрагмент кода (сокращенный):

long m = (-1) << (byte) 16; 

Теперь это для маскировки IP-подсети. Я знаю, что мне нужно начать с 4 блоков из 8 бит (т. Е. 4 байта), и все биты должны быть «включены»: 11111111 11111111 1111111 1111111 Затем нули сдвигаются справа, в этом случае стоит 16 бит; поэтому получаем 11111111 11111111 00000000 0000000, маску.

Но у меня есть несколько вопросов:

  1. Имеет ли 16 должен быть типа byte для этой работы?
  2. результат: long. Когда выполняется вышеописанное выражение, -1 преобразуется в - эффективно - 4x8 бит. Как Java знает, что для применения двух дополнений требуется 32 позиции/бит (длина IP-адреса), а не, скажем, 16 или 8? (Я предполагаю, что это связано с типом данных long?)
  3. Почему для дополнения -1 используется два дополнения? (Google дает вам -0b1, если вы спросите его, что -1 находится в двоичном формате. Сначала я подумал, что это может быть связано с переполнением, но это не так, не так ли?)
  4. Действительно, какие типы данных преобразуют компилятор это пока он работает с кодом, чтобы все это работало?

ОБНОВЛЕНИЕ:16 производится во время выполнения методом; Я просто поставил здесь константу в качестве примера. Оглядываясь назад, вероятно, плохая идея ...

+0

32-битное значение будет вписываться в регистр, а операция по перераспределению бит обычно будет выполняться самим процессором, то, что в сборке будет выглядеть как 'shl AX, 16'. На этом уровне действительно нет типов данных. Вы получили только 8, 16, 32 или 64 бит. – GolezTrol

+1

32 бита почти наверняка имеют больше общего с тем, что int is 32bits wide, чем длина IP-адреса (также, насколько я помню, когда битверение в Java, все автоматически распространяется на int) – Luke

+1

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

ответ

2

Это на самом деле заблуждение, что ваш m переменная имеет long типа, потому что IP-адрес является 32-битным и соответствует int. Ваша правая сторона действительно int и только после того, как она полностью вычислена, она расширена до long (64-разрядная версия). Отвечая на ваши вопросы:

  1. Это не так. Вы можете удалить бросок.
  2. Результат на самом деле относится к типу int, но преобразуется в long, так как это требует тип m.
  3. Дополнение от 2 до сих пор не применяется ни к чему. Номер -1: закодирован в дополнении 2. Вам нужно some способ представлять отрицательные числа только с битами. Плюс, здесь два дополнения играют побочную роль: примерно -1 кодируются как все 1 бит.
  4. Это всего лишь блок из 32 отдельных бит, сдвинутых влево, нулевая заполняющая вакансия. Затем, чтобы преобразовать в long, еще 32 бита добавлены с левой стороны.
+0

Хорошо, так, следующий daft вопрос: все ли цифры в Java, закодированные с дополнением? Если это так, означает ли это, что, хотя целое число на 32 бита длинное/большое на Java, оно действительно содержит только 31 бит числовых данных, а ведущий бит используется для указания, является ли это положительным или отрицательным числом? (I.e., является MSB всегда знаковым битом?) – Christian

+1

Все _signed integers_ находятся в двух дополнениях, и это совсем не специфично для Java. На самом деле нет другого репрезентативного предложения. Я бы не отделял «числовые данные» от знака, потому что все 32 бита одинаково взаимодействуют в представлении 2^32 различных целых чисел. –

6

Действительно, что делает типы данных компилятор преобразует это в то время как это работает код, чтобы заставить все это работать?

Этот

(-1) << (byte) 16; 

является constant expression. Его значение известно во время компиляции. Это long со значением -65536 (в десятичном представлении).

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

Возьмем, к примеру

int i = -1; 
long m = i << (byte) 16; 

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

The JLS states the following concerning shift operators and their operands

Унарное числовое расширение (§5.6.1) выполняется на каждом операнде отдельно.

which is

В противном случае, если операнд имеет тип байт во время компиляции, короткие, или полукокса, он повышен до значения типа Int с помощью расширяющегося примитивной преобразования (§5.1.2) ,

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

Результатом выражения будет значение типа int (32 бита). Он должен быть назначен переменной long (64 бита), поэтому перед назначением будет значение widened to a long.

От JLS again

Интегральные типы байт, короткие, Int, и долго, значения которых являются 8-бит, 16 бит, 32-бит и 64-разрядные подписанные дополнительном коде дополнением целые числа, соответственно и char, значениями которых являются 16-разрядные целые числа без знака , представляющие кодовые единицы UTF-16 (§3.1).

Вот как они хранятся.

+0

Nitpick: Кажется, вы противоречите себе. «Результатом выражения является значение типа int» и «Это длинное значение». – Taemyr

+0

@Teemyr Лучше? –

+0

Итак, в менее академических выражениях числа с обеих сторон - 'int', но - потому что это операция на уровне бит - мы смотрим на их битовые значения/представления? И поскольку целое число в Java составляет 32 бита, и благодаря дополнению двух, '-1 'означает 32' 1 'биты (когда мы смотрим на его представление битов)? – Christian