首页 > 关于c语言中返回不定长数据的设计问题

关于c语言中返回不定长数据的设计问题

c语言中实现这样一个需求,根据某个key值查询到一个value值,这个value值的长度是不固定的,这种情况下怎样设计代码更合理一些,我想到了几种方法:
1.在查询函数内部根据申请到的长度,申请一段内存。
2.在查询函数外部给定一个足够长的内存,然后传递到查询函数中。
3.查询函数使用过程中必须调用两次,第一次仅仅返回查询到数据长度,在外部申请一段内存,然后再调用一次,获取查询到数据。


我觉得,查询函数根据结果动态申请内存,然后将申请内存的指针和查询结果的长度返回。然后调用者记得在不需要的时候把查询结果的内存释放掉就好了。


value的设计可以参考redis的sds字符串模块,在redis源码下sds.h、sds.c,使用C99中新增的一个特性 flexible array member。


如果你不能用C++的话。。。

  1. 要是有固定的长度上限,并且返回数据大都接近上限,建议还是避免动态分配,直接用基于栈的缓冲区。
  2. 但如果value长度参差不齐,而且可能会非常长,只能用动态分配。这时候把分配/释放操作限制在一个模块/函数里会比较好,易于挑错和日后的扩展。
    所以可以用第三种调用两次的方案。也可以在查询函数旁加一个函数,专门负责删查询函数分配的内存。

可以参考Windows内核中的RtlAnsiStringToUnicodeString方法。既可以先使用RtlAnsiStringToUnicodeSize查询长度然后预先开内存,也可以让RtlAnsiStringToUnicodeString自己开内存,但之后必须调用相关的RtlFreeUnicodeString进行释放。


在C++中,可以使用RAII,在离开作用域的时候自动清理绑定到栈上对象的资源,此时就可以在函数内分配内存,而执行到呼叫者代码块外时自动释放内存。不用惦记着给每个对象写清理代码。
如果用C的话,可以考虑用GCC编译器,它提供了cleanup属性。用cleanup修饰的变量在离开其作用域的时候,GCC会呼叫指定的清理函数。

static inline void clean_ptr(char *p) { if (p) free(p); }
#define autoclean_pchar __attribute__((cleanup(clean_ptr))) char*

void foo(){
    autoclean_pchar value = get_value(key);    // get_value分配内存
    /* ... 其他代码 ... */
}
//函数返回时自动free内存

cleanup: https://gcc.gnu.org/onlinedocs/gcc/Variable-Attributes.html


其实也就是这几种方法,要么调用者自己分配内存,要么你给它预先分配一个固定大小的内存,如果不够用,一般再多分配一倍的内存,加倍策略~


我见过的有三种:

  1. 通过参数将一段内存的起始位置和大小传入
  2. 函数自己申请内存,并且要求调用者来释放
  3. 使用静态内存,并且要求结果不再使用时才能再次调用

K-V 的话,可以参考一下 gdbm,它使用的是第二种。

【热门文章】
【热门文章】