Вопрос

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

int reverse(int x)
{
    int reversed = 0;

    reversed = (x & (0xFF << 24)) >> 24;
    reversed |= (x & (0xFF << 16)) >> 8;
    reversed |= (x & (0xFF << 8)) << 8;
    reversed |= (x & 0xFF) << 24;

    return reversed;
}

Если вы пройдете 0xFF000000 Для этой функции первое назначение приведет к 0xFFFFFFFF. Отказ Я не очень понимаю, что происходит, но я знаю, что это есть что связано с коншивными образой и вперед между подписанными и неподписанными, или что-то в этом роде.

Если я либо добавим ul к 0xFF Работает нормально, что я предполагаю, потому что он вынужден без знакомства, затем преобразован в подписанный или что-то в этом направлении. Полученный код также меняется; без ul Спецификатор он использует SAR (Сдвиг арифметики справа), но в качестве без знака он использует SHR как предназначенный.

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

Заранее спасибо!

Это было полезно?

Решение

С x это подписанный количество, результат (x & (0xFF << 24)) 0xFF000000, который также подписан и, таким образом, отрицательный Номер с момента вершины (знака) установлен. То >> Оператор включен int (подписанное значение) выполняет Расширение знака (Отредактируйте: Хотя это поведение не определено и конкретно для реализации) и распространяет значение бита для знака 1, поскольку значение смещено вправо.

Вы должны переписать функцию следующим образом, чтобы работать исключительно на значения без знака:

unsigned reverse(unsigned x)
{
    unsigned int reversed = 0;

    reversed = (x & (0xFF << 24)) >> 24;
    reversed |= (x & (0xFF << 16)) >> 8;
    reversed |= (x & (0xFF << 8)) << 8;
    reversed |= (x & 0xFF) << 24;

    return reversed;
}

Другие советы

Из ваших результатов мы можем вывести, что вы находитесь на 32-битной машине.

(x & (0xFF << 24)) >> 24

В этом выражении 0xFF является int, так 0xFF << 24 тоже а int, как есть x.

Когда вы выполняете побитовые & между двумя int, результат также является int И в этом случае значение 0xFF000000 который на 32-битной машине означает, что подписанный бит установлен, поэтому у вас есть отрицательное число.

Результат выполнения правого смещения на объекте подписанного типа с отрицательным значением является определенным реализацией. В вашем случае в качестве справа от сохранения арифметического сдвига арифметики.

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

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

Просто не делай этого, это не портативно.

x Подписано, поэтому самый высокий бит используется для знака. 0xFF000000 означает «отрицательный 0x7F000000». Когда вы делаете смену, результат представляет собой «знак расширенного»: двоичная цифра, которая добавляется слева, чтобы заменить бывшую MSB, которая была смещена справа, всегда такой же, как знак значения. Так

0xFF000000 >> 1 == 0xFF800000
0xFF000000 >> 2 == 0xFFC00000
0xFF000000 >> 3 == 0xFFE00000
0xFF000000 >> 4 == 0xFFF00000

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

Если вы хотите, чтобы он работал то же самое на AL платформы с подписанными, так и без знаки целых чисел, изменение

(x & (0xFF << 24)) >> 24

в

(x >> 24) & 0xFF

Если это код Java, который вы должны использовать «>>>», который является не подпишенным правым смещением, в противном случае он будет подписать значение

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top