Запись битов внутри шестнадцатеричного массива - PullRequest
0 голосов
/ 29 сентября 2018

Извините, если название вводит в заблуждение, но я действительно не мог придумать лучшего.

У меня есть этот массив здесь:

unsigned int container[] = {0xAAAAAABB, 0xBBBBCCCC, 0xCCDDDDDD};

, и у меня есть этозначение:

0x444555

, и у меня есть эта позиция (биты):

24

Теперь позиция 24 будет указывать на то, где находится первая буква B.Мне нужно сделать эту функцию:

void write_bits(unsigned int container[], int index, unsigned int value)

, которая с параметрами, которые я дал ранее, изменила бы массив следующим образом:

unsigned int container[] = {0xAAAAAA44, 0x4555CCCC, 0xCCDDDDDD};

Сначала я попытался манипулировать битамис операциями сдвига, чтобы я мог очистить пространство для вставляемого значения:

void write_bits(unsigned int container[], int index, unsigned int value) {
    int size_of_value = 24;

    int shift_first = sizeof(int) * CHAR_BIT - index;
    int shift_second = size_of_value - shift_first;

    int cont_idx = index / (sizeof(int) * CHAR_BIT);

    vector[cont_idx] = vector[cont_idx] >> shift_first;
    vector[cont_idx] = vector[cont_idx] << shift_first;
    vector[cont_idx+1] = vector[cont_idx+1] << shift_second;
    vector[cont_idx+1] = vector[cont_idx+1] >> shift_second;

}

С параметрами, указанными ранее, это даст мне:

container[] = {0xAAAAAA00, 0x0000CCCC, 0xCCDDDDDD};

Проблема в том,что если я использую позицию 0 или 4, это не сработает.Кроме того, я не могу обернуть голову, вставив 0x444555 туда, где 0.

Ответы [ 2 ]

0 голосов
/ 30 сентября 2018

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

Например, с использованием вашей логики (с небольшим изменением имен переменных, чтобы было ясно, работаете ли вы с минимум или большинство значащих бит в элементе), вы можете сделать следующее:

void write_bits (unsigned *a, int off, unsigned v)
{
    int elembits = (int)(sizeof *a) * CHAR_BIT, /* bits per element */
        lsbits = elembits - off,                /* lsb bits in current */
        msbits = off - lsbits,                  /* msb bits in next */
        cont_idx = off / (sizeof *a * CHAR_BIT);/* current index */

    a[cont_idx] = a[cont_idx] >> lsbits;        /* clear lsits in current */
    a[cont_idx] = a[cont_idx] << lsbits;
    a[cont_idx] |= (v >> msbits);               /* set lsbits in current */

    cont_idx++; /* advance to next element */

    a[cont_idx] = a[cont_idx] << msbits;        /* clear msbits in current */
    a[cont_idx] = a[cont_idx] >> msbits;
    a[cont_idx] |= ((v >> lsbits) << msbits);   /* set msbits in current */
}

( примечание: вам нужно внимательно посмотретьпо вашей логике для определения cont_idx и проверки, будет ли число заменяемых вами битов превышать sizeof (unsigned) байт, влияющих на более чем два элемента, или же все биты, подлежащие замене, попадают в один элемент - который остаетсяВам)

Если коротко, например, использовать ваш тестовый пример, вы можете сделать:

#include <stdio.h>
#include <limits.h>

void write_bits (unsigned *a, int off, unsigned v)
{
    int elembits = (int)(sizeof *a) * CHAR_BIT, /* bits per element */
        lsbits = elembits - off,                /* lsb bits in current */
        msbits = off - lsbits,                  /* msb bits in next */
        cont_idx = off / (sizeof *a * CHAR_BIT);/* current index */

    a[cont_idx] = a[cont_idx] >> lsbits;        /* clear lsits in current */
    a[cont_idx] = a[cont_idx] << lsbits;
    a[cont_idx] |= (v >> msbits);               /* set lsbits in current */

    cont_idx++; /* advance to next element */

    a[cont_idx] = a[cont_idx] << msbits;        /* clear msbits in current */
    a[cont_idx] = a[cont_idx] >> msbits;
    a[cont_idx] |= ((v >> lsbits) << msbits);   /* set msbits in current */
}

int main (void) {

    unsigned container[] = {0xAAAAAABB, 0xBBBBCCCC, 0xCCDDDDDD},
        n = sizeof container / sizeof *container,
        v = 0x444555;

    write_bits (container, 24, v);

    fputs ("unsigned container[] = {", stdout);
    for (unsigned i = 0; i < n; i++)
        printf (i ? ", 0x%08X" : "0x%08X", container[i]);
    puts ("};");
}

Пример использования / Вывод

$ ./bin/arr-write-bits
unsigned container[] = {0xAAAAAA44, 0x4555CCCC, 0xCCDDDDDD};
0 голосов
/ 29 сентября 2018

Прежде всего необходимо уточнить типы и размеры используемых вами элементов

  • ваш массив содержит 32-битные значения, поэтому вам лучше использовать uint32_t чтобы сделать это понятным (и более переносимым).

  • значение, которое вы вставляете, составляет 24 бита (т.е. не 32 бита), поэтому вам нужно сделать этоочистить тоже, возможно, с дополнительным аргументом size.

  • Вы, похоже, используете нумерацию с прямым порядком байтов (бит 0 является наиболее значимым битом), что нормально, но вывероятно, хотите прояснить это.

Итак, ваша рутина становится:

void write_bits(uint32_t container[], unisgned offset, uint32_t value, unsigned size) {
    unsigned idx = offset/32;  // where in container to start writing
    unsigned bits = -offset % 32U;  // number of bits left to write at that position
    if (size <= bits) {
        // fits entirely within one word;
        unsigned shift = bits - size;  // how many bits up to shift value
        uint32_t mask = (UINT32_C(1) << bits) - (UINT32_C(1) << shift);
        container[idx] &= ~mask;    // clear the bits we're overwriting
        container[idx] |= value << shift;   // and write them
    } else {
        // writing into two words
        // first word...
        unsigned shift = size - bits;  // how many bits to shift down for first word
        uint32_t mask = (UINT32_C(1) << bits) - 1;
        container[idx] &= ~mask;    // clear the bits we're overwriting
        container[idx] |= value >> shift;   // and write them
        // second word...
        ++idx;
        shift = 32 - shift;
        mask = ~UINT32_C(0) << shift;
        container[idx] &= ~mask;    // clear the bits we're overwriting
        container[idx] |= value << shift;   // and write them
    }
}

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

...