# h_array **Repository Path**: phellodendron-amurense/h_array ## Basic Information - **Project Name**: h_array - **Description**: h_array数组库仓库。 - **Primary Language**: Unknown - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2024-04-15 - **Last Updated**: 2026-04-18 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # H_ARRAY是什么? H_ARRAY是一个c语言写的用于数组操作的函数库,用来新建数组、访问数组和释放数组。 H取自拼音Huang的第一个字母,ARRAY就是数组的意思。 H_ARRAY由一个头部和数组元素组成。 头部包含数组元素的数量、访问时间戳、MAGIC和数组元素的大小。 头部数据会带来额外的储存空间,但是可以保证数组的内存安全。 H_ARRAY的使用例子: ```c #include #include #include H_LOG_DECLARE_SOURCE_GLOBAL("MAIN", "h_array_example.c"); H_LOG_DECLARE_CTRL_GLOBAL("PID"); // 随意设置一个ID H_LOG_DECLARE_SINK_GLOBAL_SYSLOG("PID"); // 随意设置一个ID H_LOG_DECLARE_SINK_GLOBAL_STDOUT(); int main(int argc, char *argv[]) { H_ARRAY_DECLARE_CONTEXT(ctx); H_ARRAY_H h = NULL; H_ARRAY_H hChain1 = NULL; H_SIZE_T i; H_SIZE_T count; int *p; int n = 0; // 初始化日志 H_LOG_CTRL_GLOBAL_INIT(); //H_LOG_CTRL_GLOBAL_SET_OPTIONS(H_LOG_OPTION_ALL); H_LOG_CTRL_GLOBAL_ADD_SINK_GLOBAL_SYSLOG(); H_LOG_CTRL_GLOBAL_ADD_SINK_GLOBAL_STDOUT(); H_LOG_CTRL_GLOBAL_ADD_SOURCE_GLOBAL(); H_LOG_SET_SOURCE_GLOBAL_MASK(H_LOG_MASK_ALL); // 设置本文件全局日志源掩码 H_LOG_STACK_ADD_LOG_SOURCE2CTRL_GLOBAL(); H_LOG_STACK_SET_LOG_SOURCE_MASK(H_LOG_MASK_ALL); H_ARRAY_ADD_LOG_SOURCE2CTRL_GLOBAL(); H_ARRAY_SET_LOG_SOURCE_MASK(H_LOG_MASK_ALL); // 开始演示 H_ARRAY H_ARRAY_CLR_CTX_EX(ctx); H_ARRAY_INIT_ON_EX_GOTO_LABEL(ctx, LB_EXIT); H_LOG_INFO("h_array version: %s\n", h_array_get_version()); // 申请chain1节点链表,实际应用中也可以不申请,直接使用全局链表 H_ARRAY_NEW_CHAIN_HEAD_ON_EX_GOTO_LABEL(ctx, hChain1, "chain1", LB_EXIT); H_ARRAY_NEW_ON_EX_GOTO_LABEL(ctx, h, int, 10, LB_EXIT); H_ARRAY_FOR_EACH(ctx, int, h, i, p) { *p = n++; } H_ARRAY_FOR_EACH(ctx, int, h, i, p) { H_LOG_DEBUG("%d %d\n", i, *p); } H_ARRAY_LOG_ALL_NODE(ctx, H_LOG_LEVEL_INFO); H_ARRAY_GET_NODE_COUNT_ON_EX_GOTO_LABEL(ctx, count, LB_EXIT); H_LOG_DEBUG("Global cache node count: %" H_PRI_SIZE "\n\n", count); H_ARRAY_DELETE(ctx, h); n = 0; // 切换上下文节点链表为chain1节点链表 // 所有这个上下文新建的节点都会挂在chain1节点链表 H_ARRAY_SET_CTX_CHAIN_HEAD(ctx, hChain1); H_ARRAY_NEW_ON_EX_GOTO_LABEL(ctx, h, int, 20, LB_EXIT); H_ARRAY_FOR_EACH(ctx, int, h, i, p) { *p = n++; } H_ARRAY_FOR_EACH(ctx, int, h, i, p) { H_LOG_DEBUG("%d %d\n", i, *p); } H_ARRAY_LOG_ALL_NODE(ctx, H_LOG_LEVEL_INFO); H_ARRAY_GET_NODE_COUNT_ON_EX_GOTO_LABEL(ctx, count, LB_EXIT); H_LOG_DEBUG("Chain1 cache node count: %" H_PRI_SIZE "\n\n", count); LB_EXIT: H_ARRAY_ON_EX_LOG_EX(ctx, H_LOG_LEVEL_TRACE); H_ARRAY_DELETE(ctx, h); H_LOG_DEBUG("Chain1 leak arrays:\n"); H_ARRAY_LOG_ALL_NODE(ctx, H_LOG_LEVEL_NOTICE); // 切换回全局节点链表 H_ARRAY_CLR_CTX_CHAIN_HEAD(ctx); // 必须切换回全局节点链表才可以删除chain1节点链表 // 理由是: chain1节点链表是全局节点链表的一个节点 // 节点是哪个链表的成员, 就必须切换到哪个链表才能删除 H_ARRAY_DELETE(ctx, hChain1); H_LOG_NOTICE("Global leak arrays:\n"); H_ARRAY_LOG_ALL_NODE(ctx, H_LOG_LEVEL_NOTICE); H_ARRAY_END(ctx); // 释放日志资源 H_LOG_CTRL_GLOBAL_END(); return 0; } ``` # 开发H_ARRAY的目的 在C语言中,对数组的操作很容易产生内存泄漏、内存访问越界等问题。 开发H_ARRAY的目的就是为了解决这些问题。 # H_ARRAY如何保证内存安全 H_ARRAY采用访问时间戳来判断内存泄漏。 H_ARRAY在每次访问数组时都会更新数组的访问时间戳。 如果访问时间戳长时间不变,那么这个数组就是超时数组,很有可能被程序遗漏,很有可能是泄漏的内存。 程序员应该定时打印超时的数组,根据提示信息检查相应的源码,找出泄漏内存的地方,修正程序。 数组的超时时间应该根据具体情况决定。 H_ARRAY在访问时需要带上数组元素的类型。 内部程序通过这个类型的大小来判断访问是否和合法,如果大小不匹配,那么应该就是非法访问。 H_ARRAY还采用MAGIC来判断数组是否是非法内存。 如果MAGIC不是0xA8B4C2D1,那么被访问的数组就是非法内存。 使用`H_ARRAY_FOR_EACH`宏来遍历数组元素可以防止访问越界。 # H_ARRAY的哲理 万物皆为数组。理论上,任何东西都可以使用数组来保存,单个对象等同于元素个数为1的数组。因此,H_ARRAY几乎可以应用于程序的任何地方。 资源可以很容易使用金钱来购买得到,但是程序的稳定性和可靠性却是很难。尽管H_ARRAY需要占用额为的资源,但是建议程序都使用这个库来操作数组,以保证程序的可靠性。 # H_ARRAY库编译的方法 ```sh #如果需要生成文档,那么修改CMakeLists.txt文件,打开生成文档选项 cd build cmake .. make make docs ``` # H_ARRAY库的使用 把 h_array.h、h_array_type.h 、h_array_error.h 、h_array_call.h 、h_log.h 和 libh_array.a ( 或者 h_array.lib ) 分别拷贝到相应的头文件目录和库文件目录, 源码里面包含头文件 `#include `。 程序链接时要连接 libh_array.a。 **注意:相应的宏也要定义成一样的,请查阅CMakeLists.txt文件。** # H_ARRAY库的开发 ## 编码规范 - 采用C语言编码,禁用C++代码。 - 采用LINUX风格,可以使用astyle工具来美化代码,如: ```sh astyle --style=linux *.c *.h ``` 可以直接执行astyle.sh脚本来美化代码,如: ```sh ./astyle.sh ``` 代码提交前应该先美化代码。 - 禁止深度if语句嵌套,如: ```c if(a) { if(b) { if(c) { if(d) { //TODO SOMETHING } } } } ``` 出现这种情况时,建议采用goto语句来解决问题。goto语句的LABEL规范为LB_XXXX,如: ```c if(!a) goto LB_EXIT; if(!b) goto LB_EXIT; if(!c) goto LB_EXIT; if(!d) goto LB_EXIT; //TODO SOMETHING LB_EXIT: return; ``` - 函数和数据结构采用小写字母和下划线命名。 - 宏采用大写字母和下划线命名。 - 数据结构采用_t或者_s结尾,表示是数据结构类型,如: ```c /** * @brief 测试用的数据结构 * */ typedef struct abc_s { int a; /**< 测试数据 */ int b; /**< 测试数据 */ int c; /**< 测试数据 */ } abc_t; ``` - 函数指针类型采用_func_t结尾,表示是函数指针类型,如: ```c /** * @brief 遍历数组函数指针,用来遍历数组时回调 * @param ctx 上下文句柄,使用到的成员有: * ex 异常数据结构指针; * @see {@link h_array_ctx_s} * @param userData 用户数据,可以是任意指针 * @param array 超时的数组句柄。 */ typedef void (* h_array_walk_all_func_t)(H_CONTEXT_H ctx, H_HANDLE_T userData, H_ARRAY_H array); ``` ## 代码注释 - 代码采用JAVADOC风格。