在十六进制数组中写入位

时间:2018-09-29 18:42:07

标签: c bit-manipulation bit

很抱歉,标题误导了我,但我真的想不出更好的标题。

我在这里有这个数组:

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 :(得分:0)

遵循您的逻辑有点尴尬,但是在清除了第一个元素中的最低有效位并清除了下一个元素中的最高有效位以便为要设置的位让路之后,您要做的就是< em> shift和OR 您的替换位以替换您刚刚清除的位。

例如,使用您的逻辑(变量名称略有变化以使您清楚是对元素中的最低还是 most 位进行操作) ,您可以执行以下操作:

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};

答案 1 :(得分:-1)

第一件事是要清楚所用物品的类型和大小

  • 您的数组似乎包含32位值,因此最好使用uint32_t来使其清晰(并且更便于携带)。

  • 您要插入的值是24位(即,不是 32位),因此您也需要弄清楚这一点,可能需要附加一个size参数。

  • 您似乎正在使用big-endian位编号(位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
    }
}

这比需要的更为冗长-您可以将常见的子表达式折叠在一起以提高效率(或者让编译器的优化器为您完成此操作)。