首先说明一下,C/C++中不存在真正意义上的变长结构体。因为结构体在编译期就已经决定了其长度。如果需要实现变长,只能通过运行期分配内存来实现。
1,使用指针实现变长结构体
类似下面的代码应该非常常见:
typedef struct st_type4 { int cnt; char *data; } type_d;
我们在结构体中定义了一个data字段,且该字段是一个char型的指针。因为是指针,所以我们可以在程序中动态分配其大小,从而实现变长结构体。具体使用的例子见文章后面。
2、使用零长度数组实现变长结构体
比如下面的代码:
typedef struct st_type1 { int cnt; char item[0]; } type_a; typedef struct st_type2 { int cnt; char item[]; } type_b; typedef struct st_type3 { int cnt; char item[1]; } type_c;
这里一共列举了三种形式,主要是因为标准C或者有些编译器里面不允许零长度的数组,这个时候就可以使用第二种或者第三种形式来定义变长数组了。看一个完整的例子。
3、变长数组例子
#include <stdio.h> #include <stdlib.h> typedef struct st_type1 { int cnt; char item[0]; } type_a; typedef struct st_type2 { int cnt; char item[]; } type_b; typedef struct st_type3 { int cnt; char item[1]; } type_c; typedef struct st_type4 { int cnt; char *data; } type_d; int main() { printf("len: %ldn", sizeof(type_a)); printf("len: %ldn", sizeof(type_b)); printf("len: %ldn", sizeof(type_c)); type_a a; type_a *p_a = (type_a *)malloc(sizeof(type_a) + 100 * sizeof(char)); strcpy(p_a->item, "type_a"); printf("p_a->item:%sn", p_a->item); free(p_a); type_d d; d.data = malloc(100 * sizeof(char)); strcpy(d.data, "type_d"); printf("d.data:%sn", d.data); free(d.data); return 0; }
程序运行结果:
allan@ubuntu:temp$ ./a.out len: 4 len: 4 len: 8 p_a->item:type_a d.data:type_d
可见使用指针和使用数组实现的变长数组功能是一样的。
4、分析
既然使用指针和使用数组都可以实现变长数组,那两者各有什么优劣呢?
利用指针实现的变长数组:该方法是最传统和通用方法,也是兼容性和移植性最好的一种写法。特别是在嵌入式领域或者一些不支持C99的应用场合,这这种实现方法无疑是最保险的。其不好的地方就在于内存的管理稍微比较麻烦:一般需要先给结构体分配内存,然后再给结构体里面的指针分配内存;释放时,必须先释放指针指向的内存,再释放结构体占用的内存(如果结构体是使用类malloc之类的函数分配的内存的话)。而且这样结构体占的内存一般与指针指向的内存是不连续的。
利用数组实现的变长数组:该方法比较巧妙,其实是利用了C/C++并不检查数组“越界”这一个特点。这样分配的内存一般是连续性的,可以减小内存碎片,而且分配和释放都只需要依次,管理相对容易。
评论已关闭