Проблемы с обращением битовых сдвигов, которые превышают максимальный размер байта? - PullRequest
2 голосов
/ 09 апреля 2010

Я пытаюсь сделать простое кесарево смещение для двоичной строки, и оно должно быть обратимым. Я сделал это с помощью этого метода ..

public static String cShift(String ptxt, int addFactor)
    {
        String ascii = "";
        for (int i = 0; i < ptxt.length(); i+=8)
        {
            int character = Integer.parseInt(ptxt.substring(i, i+8), 2);
            byte sum = (byte) (character + addFactor);
            ascii += (char)sum;
        }
        String returnToBinary = convertToBinary(ascii);
        return returnToBinary;
    }

В некоторых случаях это работает нормально. Тем не менее, я думаю, что когда он переворачивается, будучи представленным одним байтом, он необратим. На тестовой строке "test!22*F " с addFactor на 12 строка становится необратимой. Почему это так и как я могу это остановить?

edit: Для пояснения тестовая строка преобразуется в двоичный файл перед передачей. Вот convertToBinary

public static String convertToBinary(String str)
    {
        char [] array = str.toCharArray();
        String binaryToBeReturned = "";

        for (int i = 0; i < str.length(); i++)
        {
            String binary = Integer.toBinaryString((int)array[i]);
            binary = padZeroes(binary);
            binaryToBeReturned += binary;
        }
        return binaryToBeReturned;
    }

Когда я запускаю это с cShift 12, а затем cShift -12 для реверса, я получаю это ...

01110100011001010111001101110100001000010011001000110010010001100010101000100000
111111111000000001110001011111111111111110000000001011010011111000111110010100100011011000101100
ÿ?qÿ?->>R6,
ÿótesÿót!22F*

Первая строка просто преобразует тестовую строку в двоичную. Вторая строка является результатом cShift в двоичном формате. Третья строка - результат преобразования ее в ascii, а четвертая строка - результат обращения с -12 в cShift и преобразования в ascii.

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

1 Ответ

1 голос
/ 09 апреля 2010

Вам нужно замаскировать byte при расширении до char, потому что в противном случае бит знака будет расширен.

ascii += (char)(sum & 0xFF)

Этот шаблон маскирования применяется при расширении числового типа со знаком, если вы не хотите расширения знака.

anInt = aByte & 0xFF;
anInt = aShort & 0xFFFF;
aLong = anInt & 0xFFFFFFFFL; // notice the L

Вот пример для иллюстрации:

byte b = -1; // 0xFF
char ch = (char) b; // 0xFFFF
int i = ch;
System.out.println(i); // prints "65535", which is 0xFFFF

byte b = -1; // 0xFF
char ch = (char) (b & 0xFF); // 0xFF
int i = ch;
System.out.println(i); // prints "255", which is 0xFF

Здесь есть урок. Если вы читали Java Puzzlers , вы увидите несколько таких, которые вращаются вокруг шумихи со знаком расширения. Эта головоломка из книги по сути та же, что и у меня выше, но, возможно, более запутанная:

// Java Puzzlers, Puzzle 6: Multicast
System.out.println((int) (char) (byte) -1); // prints 65535

Есть два способа исправить это:

  • Избегайте работы с byte и short. Тебе редко нужно.
  • Если вы работаете с ними, всегда остерегайтесь необходимости маскировать.
  • byte до char всегда сложно, потому что:
    • Хотя char шире byte ...
    • char не подписано, а byte равно !!!
    • Следовательно, это не прямое преобразование с расширением, а преобразование с расширением-сужением!

JLS 5.1.4 Расширяющие и сужающие преобразования примитивов

Следующее преобразование объединяет примитивные преобразования с расширением и сужением:

  • byte до char.

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


Дополнительные ссылки

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...