Битовое вращение со знаком char (C)? - PullRequest
0 голосов
/ 20 октября 2018

Я пытаюсь повернуть подписанный символ (*c), который в двоичном виде равен 10011010, правильные 4 (numRotate) места.Желаемый результат после смены - 10101001.Код, который у меня сейчас есть:

void right(char *c, int numRotate) {
    *c = (*c >> numRotate) | (*c << (8 - numRotate));
}

Судя по тому, что я узнал, это, очевидно, должно работать, чтобы правильно выполнить желаемую смену.Вместо этого я получил 11111001.Я не уверен, что не так.Может ли быть проблема с типами данных signed vs unsigned char?Все ресурсы, на которые я смотрел, используют только неподписанные типы данных.

Ответы [ 2 ]

0 голосов
/ 20 октября 2018

Сдвиг вправо отрицательного значения имеет поведение, определяемое реализацией.Шаблон 10011010 имеет отрицательное значение, если char имеет ширину 8 бит и подписан по умолчанию на вашей платформе.Вы должны использовать unsigned char, чтобы определить поведение для вашей цели:

void right(char *c, int numRotate) {
    *c = ((unsigned char)*c >> numRotate) | ((unsigned char)*c << (8 - numRotate));
}
0 голосов
/ 20 октября 2018

Ответ получен в другом посте Арифметическое смещение битов на целом числе со знаком .Чтобы получить ожидаемый результат, вы должны использовать unsigned char.

void right(unsigned char *c, int numRotate) {
    *c = (*c >> numRotate) | (*c << (8 - numRotate));
}

Оператор сдвига вправо со целым числом со знаком заполнит оставшееся место знаковым битом (MSB) так:

10011010 >> 4 == 11111001
01011010 >> 4 == 00000101

Ответ на вопрос, который я связал, утверждает, что это зависит от компилятора / платформы.Таким образом, общая методика оптимизации, заключающаяся в замене умножения / деления на степени 2 операциями битового сдвига, работает с отрицательными числами.Пример:

#include <stdio.h>

int main()
{
    char x = -4;
    printf("0x%x -> %i\n", x, x);

    x <<= 1; //multiply by 2^1 = 2
    printf("0x%x -> %i\n", x, x);

    x >>= 2; //divide by 2^2 =4
    printf("0x%x -> %i\n", x, x);

    return 0;
}

Вывод:

0xfffffffc -> -4
0xfffffff8 -> -8
0xfffffffe -> -2
...