`
dcj3sjt126com
  • 浏览: 1825583 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

结构体中最后一个元素是长度为0的数组

    博客分类:
  • C
阅读更多

在Linux源代码中,有很多的结构体最后都定义了一个元素个数为0个的数组,如/usr/include/linux/if_pppox.h中有这样一个结构体: 
struct pppoe_tag { 
    __u16 tag_type; 
    __u16 tag_len; 
    char tag_data[0]; 
} __attribute ((packed));

又如在asterisk的源码中的Pbx.c: 
struct  ast_ignorepat  {  
    const  char  *registrar;  
    struct  ast_ignorepat  *next;  
    char  pattern[0];  
};   
  
结构体最后的长度为0的数组是GCC中广泛使用技巧,常用来构成可变长缓冲区。 
在创建时,malloc一段结构体大小加上可变长数据长度的空间给它:malloc(sizeof(struct  pppoe_tag)+  buff_len),可变长部分按数组访问方式访问;释放时,直接把整个结构体free掉就可以了。

例子如下: 
struct pppoe_tag *sample_tag; 
__u16 sample_tag_len = 10; 
sample_tag = (struct pppoe_tag *)malloc( sizeof(struct pppoe_tag) + sizeof(char) * sample_tag_len); 
sample_tag->tag_type = 0xffff; 
sample_tag->tag_len = sample_tag_len; 
sample_tag->tag_data[0]=…. 

释放时: 
free(sample_tag)

这样的好处有两个:  
一次分配解决问题,省了不少麻烦。为了防止内存泄漏,如果是分两次分配(结构体和缓冲区),那么要是第二次malloc失败了,必须回滚释放第一个分配的结构体。这样带来了编码麻烦。

其次,分配了第二个缓冲区以后,如果结构里面用的是指针,还要为这个指针赋值。同样,在free这个buffer的时候,用指针也要两次free。而且小内存的管理是非常困难的,如果用指针,这个buffer的struct部分就是小内存了,在系统内存在多了势必严重影响内存管理的性能。要是用空数组把struct和实际数据缓冲区一次分配大块问题,就没有这个问题。

所以,结构体最后使用0或1的长度数组的原因,主要是为了方便的管理内存缓冲区,如果你直接使用指针而不使用数组,那么,你在分配内存缓冲区时,就必须分配结构体一次,然后再分配结构体内的指针一次,(而此时分配的内存已经与结构体的内存不连续了,所以要分别管理即申请和释放)而如果使用数组,那么只需要一次就可以全部分配出来;反过来,释放时也是一样,使用数组,一次释放,使用指针,得先释放结构体内的指针,再释放结构体。还不能颠倒次序。

这个技巧其实就是分配一段连续的的内存,减少内存的碎片化。在Linux操作系统开发或者嵌入式开发,这种技巧尤其常见。

PS:某些编译器不支持长度为0的数组的定义,在这种情况下只要将它定义成char tag_data[1],使用方法相同。

分享到:
评论

相关推荐

    利用串口传输结构体数据

    结构体是一种数据的归类方式,相比数组或变量更具有整体全面性,例如一个数组只可以放一些按照元素顺序存放的单元变量,即 buffer = {x, x, x, x, x…},i 有多大,数组内元素就有多少。那么我们这时候如果我们用这...

    各字符出现个数.txt

    3.直接为CharNums结构体数组中的第一个元素赋值,其中字符设置为字符数组中的第一个元素,出现次数为1,并设置变量count为1 4.之后字符数组中每一个字符均与CharNums结构体数组中所有字符进行逐一比较。若存在相同...

    C语言变长数组 struct中char data[0]的用法详解

    今天在看一段代码时出现了用结构体实现变长...在结构中,data是一个数组名;但该数组没有元素;该数组的真实地址紧随结构体MyData之后,而这个地址就是结构体后面数据的地址(如果给这个结构体分配的内容大于这个结构体

    数组操作:创建、插入、排序、删除

    用结构体创建一个数组,对数组进行了基本的操作,包括数组的插入、删除、排序、求长度等

    纯C语言实现顺序表附加源码

    1. 定义顺序表的结构体:顺序表的结构体包含两个成员变量,一个是指向存储数据的数组的指针,另一个是记录当前顺序表中元素的个数。 2. 初始化顺序表:初始化顺序表时,将顺序表的长度设置为0。 3. 插入元素:在顺序...

    C语言柔性数组实例详解

    一般来说,结构中最后一个元素允许是未知大小的数组,这个数组就是柔性数组。但结构中的柔性数组前面必须至少一个其他成员,柔性数组成员允许结构中包含一个大小可变的数组,sizeof返回的这种结构大小不包括柔性数组...

    二级上机真题例典—编程

    移动数组元素到另一数组 大小写转换 删除指定的字符 子字符串查找 字符统计 字符串逆置 回文数 数字字符串转换成整数 比较字符串长度 子字符串移动 字符串连接 在链表中查找元素 结构体和链表排序 求链表中的极值

    Go语言学习笔记 – 第四章 复合数据类型(The Go Programming Language)

    第四章 复合数据类型 四种符合数据类型:数组、slice、map和结构体 数组和结构体是聚合类型 数组是由同构的元素组成 结构体则是由异构的元素组成 slice和map则是动态的数据结构,它们将根据...数组的长度是数组类型的一

    数据结构(C++)有关练习题

    <br>实验四 综合(课程设计) 内容及步骤: 1、假定一维数组a[n]中的每个元素值均在[0,200]区间内,用C++编写一个算法,分别统计出落在[0,20],[21,50],[51,80],[81,130],[131,200]等各区间内的元素...

    C人事信息管理系统

    要求用户输入一条新的员工信息,这些信息保存在结构体类型数组中空的元素的各字段中,并写入到文件中进行保存; 3)系统修改功能 根据用户输入的待修改的员工编号,查找该员工的编号的记录,若找到该记录,则修改除...

    明解C语言(第3版)入门篇.[日]柴田望洋(带详细书签).pdf 【半高清】

    数组的元素个数 135 5-2 多维数组 138 多维数组 138 总结 142 第6章 函数 145 6-1 什么是函数 146 main函数和库函数 146 什么是函数 146 函数定义 147 函数调用 148 三个数中的最大值 151 将函数的返回值...

    Go基础Slice教程详解

    Go 数组的长度不可改变,在特定场景中这样的集合就不太适用,Go中提供了一种灵活,功能强悍的内置类型切片(“动态数组”),与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大。...

    Golang2-new.docx

    5.2. 一个递归函数的例子( recursive functions) 121 5.3. 多返回值 121 5.4. 命名返回值 121 5.5. 可变函数参数 122 5.6. Defer 123 5.6.1. Defer语句介绍 123 5.6.2. Defer使用场景 128 5.7. 什么是头等...

    compare, alltrue:逐个元素比较结构、单元格和数组-matlab开发

    % A 和 B 必须属于同一类型,并且属于以下类型之一: % 结构体、元胞数组、数值或逻辑数组或字符串。 % A 和 B 可能包含以上所列类型的其他元素(如果它们% 是元胞数组或结构)。 % 如果 A 和 B 是结构体,和/或...

    C语言讲义.doc

    4.1.4 指定结构体元素的位字段 72 4.1.5 结构数组 72 4.1.6 嵌套结构 73 4.1.7 结构体的赋值 73 4.1.8 指向结构体的指针 73 4.1.9 指向结构体数组的指针 73 4.1.10 结构中的数组成员和指针成员 73 4.1.11 在堆中创建...

    语言程序设计课后习题答案

    面向对象方法中的对象,是系统中用来描述客观事物的一个实体,它是用来构成系统的一个基本单位,由一组属性和一组行为构成。 面向对象的方法将数据及对数据的操作方法放在一起,作为一个相互依存、不可分离的整体--...

    电话薄管理系统C语言

    /*在数组temp中查找编号为searchinput值的元素,并返回该数组元素的下标值*/ if(p!=-1) /*若找到该记录*/ { printheader(); printdata(temp[p]); printf(END); printf("press any key to return"); getchar...

    软件课程设计 试验报告 代码 演示

    根据上面的流程图可以看到如果是一步一步的写程序,势必会让程序变得冗长且不易阅读,因而我想到使用循环的方法,将流程图中类似的结构体做成一个循环体来实现,使程序源代码变得十分的简洁,且容易被阅读和修改。...

    C语言经典例题100道

    计算一个字符串长度 71.编写输入/输出函数 72.创建链表 73.反向输出链表 74.连接两个链表 75.算一道简单题目 76.调用函数求1/2+1/4+...+1/n 77.填空练习(指向指针的指针) 78.找到年龄最大的人 79.字符串排序 80....

    splitFV - 拆分网格:将由面和顶点定义的 2D 或 3D 网格拆分为单独连接的网格块。-matlab开发

    的每个元素这个数组表示一个单独连接的补丁。 FVOUT = SPLITFV(FV) 将 FV 作为具有“面”和“顶点”字段的结构体 例如: fullpatch.vertices = [2 4; 2 8; 8 4; 8 0; 0 4; 2 6; 2 2; 4 2; 4 0; 5 2; 5 0]; ...

Global site tag (gtag.js) - Google Analytics