正文
大家好,我是bug菌~
如今嵌入式软件按照平台来分主要是两大派系,玩单片机和玩嵌入式Linux,相对而言单片机这块的资源更是不够用,当然现在很多单片机的主频贼高,内存贼大,资源贼丰富,那我还要考虑资源受限的问题吗?
需要的,在成本面前没有最低,只有更低,当技术壁垒一旦被打破,拼的就是成本,多少公司的产品可以做得跟主流厂家一模一样,但就是成本压不下来,导致报价偏高,常常丢标。
那么在单片机开发中,内存是极其宝贵的资源,一些8位单片机可能只有几KB的RAM,当然有时候flash也比较少,但绝大多数情况都没有RAM那么稀缺,如何高效利用每一个bit都是工程师们必须面对的挑战。
那么今天bug菌就介绍下位数组小技巧,从而更加紧凑地存储和操作布尔值,管理大量布尔状态、标志位或设备状态的场景还是比较好用的。
1
bit数组
简单点就是定义一个数组,通过制作一些接口可以便捷的操作所定义数组中每个bit,很多朋友在项目中也是这么用的,但可能没有封装,整理一下或许以后更加方便。
1. 数据结构定义
#ifndef BIT_ARRAY_H #define BIT_ARRAY_H #include <stdint.h> #include <stdbool.h> // 位数组结构体 typedefstruct { uint8_t *data; // 存储数据的字节数组 uint32_t bit_count; // 总位数 uint32_t byte_size; // 需要的字节数 } BitArray; // 错误码 typedefenum { BITARRAY_OK = 0, BITARRAY_ERROR_INVALID_INDEX, BITARRAY_ERROR_NULL_POINTER, BITARRAY_ERROR_INVALID_SIZE } BitArrayError; #endif这里的*data就是指针指向一篇连续的内存,通常是用后面初始化函数传入的buffer数组,bit_count和byte_size都是标识*data所指向的内存有多大。bitArrayError是一些防御性编程的枚举数值。
2. 基础操作宏
// 计算存储指定位数所需的字节数 #define BITARRAY_BYTES_NEEDED(bits) (((bits) + 7) / 8) // 获取位索引所在的字节位置 #define BITARRAY_BYTE_INDEX(bit_index) ((bit_index) >> 3) // 获取位在字节内的位置(0-7) #define BITARRAY_BIT_POS(bit_index) ((bit_index) & 0x07) // 创建位掩码 #define BITARRAY_BIT_MASK(bit_index) (1U << BITARRAY_BIT_POS(bit_index))这里是一些基础的宏,为了后面封装函数,不至于晦涩难懂。其实都是一个常规的操作,也比较经典,如果觉得看起来有点吃力,那还得多敲敲代码了,记得都是按照1个byte对应8bit来处理的。
3. 实现
下面是相对比较完整的实现,大家也可以根据自己的项目进行调整和要优化,比如注意在具体平台的大小端问题,线程安全问题等等。
// bitarray.c #include "bitarray.h" /** * @brief 初始化位数组 * @param array 位数组指针 * @param buffer 存储缓冲区 * @param buffer_size 缓冲区大小(字节) * @param bit_count 需要的总位数 * @return 初始化结果 */ BitArrayError bitarray_init(BitArray *array, uint8_t *buffer, uint32_t buffer_size, uint32_t bit_count) { if (!array || !buffer) { return BITARRAY_ERROR_NULL_POINTER; } uint32_t required_bytes = BITARRAY_BYTES_NEEDED(bit_count); if (buffer_size < required_bytes) { return BITARRAY_ERROR_INVALID_SIZE; } if (bit_count == 0) { return BITARRAY_ERROR_INVALID_SIZE; } array->data = buffer; array->bit_count = bit_count; array->byte_size = required_bytes; // 清零所有位 bitarray_clear_all(array); return BITARRAY_OK; } /** * @brief 设置指定位为1 * @param array 位数组指针 * @param bit_index 位索引(0 ~ bit_count-1) * @return 操作结果 */ BitArrayError bitarray_set(BitArray *array, uint32_t bit_index) { if (!array) return BITARRAY_ERROR_NULL_POINTER; if (bit_index >= array->bit_count) return BITARRAY_ERROR_INVALID_INDEX; uint32_t byte_idx = BITARRAY_BYTE_INDEX(bit_index); uint8_t bit_mask = BITARRAY_BIT_MASK(bit_index); array->data[byte_idx] |= bit_mask; return BITARRAY_OK; } /** * @brief 清除指定位(设为0) * @param array 位数组指针 * @param bit_index 位索引 * @return 操作结果 */ BitArrayError bitarray_clear(BitArray *array, uint32_t bit_index) { if (!array) return BITARRAY_ERROR_NULL_POINTER; if (bit_index >= array->bit_count) return BITARRAY_ERROR_INVALID_INDEX; uint32_t byte_idx = BITARRAY_BYTE_INDEX(bit_index); uint8_t bit_mask = BITARRAY_BIT_MASK(bit_index); array->data[byte_idx] &= ~bit_mask; return BITARRAY_OK; } /** * @brief 获取指定位的值 * @param array 位数组指针 * @param bit_index 位索引 * @param value 存储位值的指针 * @return 操作结果 */ BitArrayError bitarray_get(const BitArray *array, uint32_t bit_index, bool *value) { if (!array || !value) return BITARRAY_ERROR_NULL_POINTER; if (bit_index >= array->bit_count) return BITARRAY_ERROR_INVALID_INDEX; uint32_t byte_idx = BITARRAY_BYTE_INDEX(bit_index); uint8_t bit_mask = BITARRAY_BIT_MASK(bit_index); *value = (array->data[byte_idx] & bit_mask) != 0; return BITARRAY_OK; } /** * @brief 切换指定位(0变1,1变0) * @param array 位数组指针 * @param bit_index 位索引 * @return 操作结果 */ BitArrayError bitarray_toggle(BitArray *array, uint32_t bit_index) { if (!array) return BITARRAY_ERROR_NULL_POINTER; if (bit_index >= array->bit_count) return BITARRAY_ERROR_INVALID_INDEX; uint32_t byte_idx = BITARRAY_BYTE_INDEX(bit_index); uint8_t bit_mask = BITARRAY_BIT_MASK(bit_index); array->data[byte_idx] ^= bit_mask; return BITARRAY_OK; } /** * @brief 设置所有位为1 * @param array 位数组指针 * @return 操作结果 */ BitArrayError bitarray_set_all(BitArray *array) { if (!array) return BITARRAY_ERROR_NULL_POINTER; for (uint32_t i = 0; i < array->byte_size; i++) { array->data[i] = 0xFF; } // 清除多余的位(如果总位数不是8的倍数) uint32_t extra_bits = array->bit_count & 0x07; if (extra_bits > 0) { uint8_t mask = (1U << extra_bits) - 1; array->data[array->byte_size - 1] &= mask; } return BITARRAY_OK; } /** * @brief 清除所有位为0 * @param array 位数组指针 * @return 操作结果 */ BitArrayError bitarray_clear_all(BitArray *array) { if (!array) return BITARRAY_ERROR_NULL_POINTER; for (uint32_t i = 0; i < array->byte_size; i++) { array->data[i] = 0x00; } return BITARRAY_OK; } /** * @brief 检查所有位是否都为0 * @param array 位数组指针 * @param is_empty 存储结果的指针 * @return 操作结果 */ BitArrayError bitarray_is_empty(const BitArray *array, bool *is_empty) { if (!array || !is_empty) return BITARRAY_ERROR_NULL_POINTER; for (uint32_t i = 0; i < array->byte_size; i++) { if (array->data[i] != 0) { *is_empty = false; return BITARRAY_OK; } } *is_empty = true; return BITARRAY_OK; }最后
好了,今天就跟大家分享这么多了,如果你觉得有所收获,一定记得点个赞~
唯一、永久、免费分享嵌入式技术知识平台~
推荐专辑 点击蓝色字体即可跳转
☞MCU进阶专辑
☞嵌入式C语言进阶专辑
☞“bug说”专辑
☞专辑|Linux应用程序编程大全
☞专辑|学点网络知识
☞专辑|手撕C语言
☞专辑|手撕C++语言
☞专辑|经验分享
☞专辑|电能控制技术
☞专辑 | 从单片机到Linux