切片一个 uint8_t 数组

Posted

技术标签:

【中文标题】切片一个 uint8_t 数组【英文标题】:Slice up an uint8_t array 【发布时间】:2016-07-14 09:15:02 【问题描述】:

假设我有一个包含 16 个 uint8_t 的数组,如下所示:

uint8_t array[] = 0x13, 0x01, 0x4E, 0x52, 0x31, 0x4A, 0x35, 0x36, 0x4C, 0x11, 0x21, 0xC6, 0x3C, 0x73, 0xC2, 0x41;

此数组存储包含在外部外围设备的 128 位寄存器中的数据。它所代表的一些信息存储在 2、3、8、12 位......等等。

什么是最好和最优雅的方式来分割它并掩码我需要的信息? (问题是我需要的一些东西与数组的一个单元格的长度重叠)

如果有帮助,我编写的这个 sn-p 将整个数组转换为 char* 字符串。但是将其转换为 int 不是选项,因为......好吧 16 个字节。

int i;
char str[33];
for(i = 0; i < sizeof(array) / sizeof(*array) ; i++) 
    sprintf(str+2*i,"%02hX",array[i]);

puts(str); 

13014E52314A35364C1121C63C73C241

【问题讨论】:

您的str 太短,如果sizeof(array) &gt;= 8,您的程序将调用未定义的行为 以取消引用超出范围。它应该至少有 33 个 (2 * 16 + 1) 字符长。另外不要忘记在将数据传递给puts() 之前通过添加'\0' 来终止字符串。还有一点就是sizeof(array) / sizeof(*array)获取数组元素个数应该更安全。 你说得对,奇怪的是它在编译或运行时都没有产生任何错误......即使没有为其分配内存,它也只会打印出整个内容。无论如何,这只是思想的食物,我正在编辑它以使其正确,谢谢 啊,我注意到sprintf()会终止字符串,所以你不必自己做。 正是我刚刚输入的内容。我刚刚在调试中尝试过,它确实终止了字符串 不可移植,但您可以在打包数据结构中使用位域 【参考方案1】:

实际上,在尝试解析各种比特流时也会出现此类问题,例如视频或图像文件或通过 LZ* 等算法压缩的数据。所以这里使用的方法是实现一个比特流读取器。

但在您的情况下,位序列是固定长度且非常短,因此一种方法是使用按位运算手动检查字段值。

或者你可以使用我刚刚写的这个函数,它可以从一个 uint8 数组中提取任意数量的位,从所需的位位置开始:

uint32_t extract_bits(uint8_t *arr, unsigned int bit_index, unsigned int bit_count)

    /* Assert that we are not requested to extract more than 32 bits */
    uint32_t result = 0;
    assert(bit_count <= sizeof(result)*8 && arr != NULL);

    /* You can additionally check if you are trying to extract bits exceeding the 16 byte range */
    assert(bit_index + bit_count <= 16 * 8);

    unsigned int arr_id = bit_index / 8;
    unsigned int bit_offset = bit_index % 8;

    if (bit_offset > 0) 
        /* Extract first 'unaligned_bit_count' bits, which happen to be non-byte-aligned.
         * When we do extract those bits, the remaining will be byte-aligned so
         * we will thread them in different manner.
         */
        unsigned int unaligned_bit_count = 8 - bit_offset;

        /* Check if we need less than the remaining unaligned bits */
        if (bit_count < unaligned_bit_count) 
            result = (arr[arr_id] >> bit_offset) & ((1 << bit_count) - 1);
            return result;
        

        /* We need them all */
        result = arr[arr_id] >> bit_offset;
        bit_count -= unaligned_bit_count;

        /* Move to next byte element */
        arr_id++;
    

    while (bit_count > 0) 
        /* Try to extract up to 8 bits per iteration */
        int bits_to_extract = bit_count > 8 ? 8 : bit_count;

        if (bits_to_extract < 8) 
            result = (result << bits_to_extract) | (arr[arr_id] & ((1 << bits_to_extract)-1));
        else 
            result = (result << bits_to_extract) | arr[arr_id];
        

        bit_count -= bits_to_extract;
        arr_id++;
    

    return result;

这里是它的使用示例。

uint32_t r;

/* Extracts bits [7..8] and places them as most significant bits of 'r' */  
r = extract_bits(arr, 7, 2)

/* Extracts bits [4..35] and places them as most significant bits of 'r' */  
r = extract_bits(arr, 4, 32);

/* Visualize */
printf("slice=%x\n", r);

然后r 的可视化取决于您。它们可以表示为十六进制双字、字符,也可以由您决定。

【讨论】:

非常感谢,这太棒了。我有点像这样写一些东西,但你的代码要干净得多哈哈。经过测试,工作正常。

以上是关于切片一个 uint8_t 数组的主要内容,如果未能解决你的问题,请参考以下文章

如何将字符数组转换为 uint8_t

以编程方式填充 uint8_t 数组

c char 数组到 uint8_t 数组

uint8_t 数组的数组

将 unsigned char 数组转换为 uint8_t 数组?

将 uint8_t 数组传递给方法