Вопрос по c – Побитовый сдвиг массива символов

11

У меня есть массив символов, которые я пытаюсь сдвинуть вправо по битам>>, затем& с другим массивом. Я думаю, что я неправильно понял, как это сделать.

Я думал, хотя это был набор символов, просто заявляяmy_array >>= 1 переместил бы все, но я получаю ошибку:"error: invalid operands to binary >> (have ‘char[8]’ and ‘int’)"

Побитовое сравнение, которое я пытаюсь сделать, с массивом одинакового размера, инициированным для всех "0" ... для этого я получаю:"error: invalid operands to binary & (have ‘char *’ and ‘char *’)"

Нужно ли преобразовывать эти массивы во что-то еще, прежде чем я смогу сдвинуть и сравнить?

Извините, я не был супер ясен ... Все отличные советы до этого момента, и я думаю, что я понимаю больше, что нет супер простого способа сделать это. Более конкретно, то, что я пытаюсь сделать, это сдвинуть биты массива символов ВСЕХ вправо 1, добавив бит, сдвинутый вправо назад в крайнюю левую часть массива, выполнить побитовое сравнение с другим массивом того же размера.

Технически сравнение не должно быть массивом с массивом ... Мне просто нужны биты. Было бы проще преобразовать массив во что-то еще, прежде чем пытаться выполнить сдвиги / сравнения?

Вы пытаетесь повернуть содержимое массива или пытаетесь поразрядно сдвинуть каждый отдельный элемент массива? Ни одна из этих операций изначально не существует в C. Вам нужно написать цикл, который либо копирует каждый элемент вниз на одну позицию, либо сдвигает по битам каждый элемент в массиве. chrisaycock

Ваш Ответ

7   ответов
12

Тебе нужно сдвинуть и сравнить поэлементно.

for(i = 0; i < len; ++i)
    array[i] >>= 3;

например. Если вы хотите переместить биты, сдвинутые от одного элемента к другому, это более сложно, скажем, вы сдвигаете вправо, тогда

unsigned char bits1 = 0, bits2 = 0;
for(i = len-1; i >= 0; --i) {
    bits2 = array[i] & 0x07;
    array[i] >>= 3;
    array[i] |= bits1 << 5;
    bits1 = bits2;
}

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

2

как смещение / OR / XOR / AND / и т.д .. на массивах, вы должны выполнять это в цикле, вы не можете выполнить это непосредственно в массиве.

1

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

//https://github.com/ashvin-bhuttoo/CryptoTest/blob/master/CryptoTest/Crypto.cpp
//CRYPTO CONFIGURATION PARAMETERS
#define BIT_SHIFT 3
#define XOR_KEY 0x3C
#define ENABLE_XOR_VARIANCE true
////////////////////////////////

int get_rs_mask(int shift)
{
    switch (shift)
    {
    case 0:
        return 0x00;
    case 1:
        return 0x01;
    case 2:
        return 0x03;
    case 3:
        return 0x07;
    case 4:
        return 0x0F;
    case 5:
        return 0x1F;
    case 6:
        return 0x3F;
    case 7:
        return 0x7F;
    default:
        throw "get_rs_mask -> Error, shift argument outside legal range 0-7";
    }
}

void shift_right(char* buf, int msg_len, int shift)
{
    unsigned char tmp = 0x00, tmp2 = 0x00;
    for (int k = 0; k <= msg_len; k++)
    {
        if (k == 0)
        {
            tmp = buf[k];
            buf[k] >>= shift;
        }
        else
        {
            tmp2 = buf[k];
            buf[k] >>= shift;
            buf[k] |= ((tmp & get_rs_mask(shift)) << (8 - shift));

            if (k != msg_len)
                tmp = tmp2;
        }
    }
}

int get_ls_mask(int shift)
{
    switch (shift)
    {
    case 0:
        return 0x00;
    case 1:
        return 0x80;
    case 2:
        return 0xC0;
    case 3:
        return 0xE0;
    case 4:
        return 0xF0;
    case 5:
        return 0xF8;
    case 6:
        return 0xFC;
    case 7:
        return 0xFE;
    default:
        throw "get_ls_mask -> Error, shift argument outside legal range 0-7";
    }
}

void shift_left(char* buf, int msg_len, int shift)
{
    char tmp = 0x00, tmp2 = 0x00;
    for (int k = msg_len; k >= 0; k--)
    {
        if (k == msg_len)
        {
            tmp = buf[k];
            buf[k] <<= shift;
        }
        else
        {
            tmp2 = buf[k];
            buf[k] <<= shift;
            buf[k] |= ((tmp & get_ls_mask(shift)) >> (8 - shift));

            tmp = tmp2;
        }
    }
}

void crypt(char* buf, int msg_len, bool decrypt = false)
{
    if (!decrypt)
    {
        shift_right(buf, msg_len, BIT_SHIFT);
        for (int k = 0; k < msg_len; k++)
        {
            buf[k] = buf[k] ^ XOR_KEY ^ k * (ENABLE_XOR_VARIANCE ? 2 : 0);
        }
        buf[msg_len] = '\0';
    }
    else
    {
        for (int k = 0; k < msg_len; k++)
        {
            buf[k] = buf[k] ^ XOR_KEY ^ k * (ENABLE_XOR_VARIANCE ? 2 : 0);
        }
        shift_left(buf, (msg_len)-1, BIT_SHIFT);
    }
}
3
/** Shift an array right.
 * @param ar The array to shift.
 * @param size The number of array elements.
 * @param shift The number of bits to shift.
 */
void shift_right(unsigned char *ar, int size, int shift)
{
    int carry = 0;                              // Clear the initial carry bit.
    while (shift--) {                           // For each bit to shift ...
        for (int i = size - 1; i >= 0; --i) {   // For each element of the array from high to low ...
            int next = (ar[i] & 1) ? 0x80 : 0;  // ... if the low bit is set, set the carry bit.
            ar[i] = carry | (ar[i] >> 1);       // Shift the element one bit left and addthe old carry.
            carry = next;                       // Remember the old carry for next time.
        }   
    }
}   
Ну, это странно, или я что-то упустил. Это выглядит как сочетание сдвига вправо и сдвига влево. Комментарий рядом с битом переноса гласит «Сдвиньте элемент на один бит влево», но он сдвигается вправо. И цикл for идет от высокой к низкой, я бы предпочел перейти от низкой к высокой для смещения вправо. Andre Miras
Также я бы переместил "int carry = 0;" внутри цикла while непосредственно перед циклом for. Andre Miras
Это очень неэффективно. Если вы хотите сдвинуть массив на 7 битов, то каждый символ в массиве будет повторяться 7 раз. Очень неэффективно. Jack Giffin
2

те сравнить два из них, вам нужно будет делать это поэлементно.)

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

Если вам нужно такое поведение перехода в следующий байт, и вы не возражаете против того, чтобы сделать ваш код неприятным, непереносимым и подверженным ошибкам, вы можете взять указатель на массив, привести его к чему-то вродеunsigned long long *, разыменовываем его, сдвигаем полученное целое число и сохраняем его снова.

НО, если это поведение, которое вы хотите, то вы должны использовать целое число вместоchar[8] начать с

(Если бы вы могли больше рассказать о том, чего вы на самом деле хотите достичь, тогда могут быть более полезные ответы.)

2

символ (или целое число). Вы не можете сдвинуть весь массив. Сдвигmy_array пытается выполнить операцию сдвига для типа массива (или указателя на символ), что невозможно. Сделайте это вместо этого:

for (i = 0; i < size; i++) {
  my_array[i] >>= 1;
}

Кроме того, вы должны быть осторожны с символами, потому что они обычно подписаны, а символ, содержащий отрицательное значение, принесет «1» слева вместо нулей. Поэтому лучше использовать неподписанные символы.

РЕДАКТИРОВАТЬ Приведенный выше код упрощен. Если вы намеревались сдвинуть вправо массив целиком, а не только каждый байт, то вам нужно «вручную» скопировать каждый LSB в MSB байта справа от него. Посмотрите на ответ Ричарда Пеннингтона.

Я предполагаю, что он хочет обрабатывать массив как одно значение, поэтому вам придется перенести немного и из более значимого байта. loganfsmyth
Правильно, я отредактировал свой ответ. Благодарност Israel Unterman
0
/**
 * shift a number of bits to the right
 *
 * @param   SRC         the array to shift
 * @param   len         the length of the array
 * @param   shift       the number of consecutive bits to shift
 *
*/
static void shift_bits_right(uint8_t SRC[], uint16_t len, uint32_t shift) {
    uint32_t i = 0;

    uint8_t start = shift / 8;
    uint8_t rest = shift % 8;
    uint8_t previous = 0;

    for(i = 0; i < len; i++) {
        if(start <= i) {
            previous = SRC[i - start];
        }
        uint8_t value = (previous << (8 - rest)) | SRC[i + start] >> rest;
        SRC[i + start] = value;
    }
}

Похожие вопросы