struct bio {
sector_t bi_sector; /* 磁盘上相关扇区 */
struct bio *bi_next; /* 请求列表 */
struct block_device *bi_bdev; /* 相关的块设备 */
unsigned long bi_flags; /* 状态和命令标志 */
unsigned long bi_rw; /* 读还是写 */
unsigned short bi_vcnt; /* bio_vecs的数目 */
unsigned short bi_idx; /* bio_io_vect的当前索引 */
/* Number of segments in this BIO after
* physical address coalescing is performed.
* 结合后的片段数目
*/
unsigned int bi_phys_segments;
unsigned int bi_size; /* 剩余 I/O 计数 */
/*
* To keep track of the max segment size, we account for the
* sizes of the first and last mergeable segments in this bio.
* 第一个和最后一个可合并的段的大小
*/
unsigned int bi_seg_front_size;
unsigned int bi_seg_back_size;
unsigned int bi_max_vecs; /* bio_vecs数目上限 */
unsigned int bi_comp_cpu; /* 结束CPU */
atomic_t bi_cnt; /* 使用计数 */
struct bio_vec *bi_io_vec; /* bio_vec 链表 */
bio_end_io_t *bi_end_io; /* I/O 完成方法 */
void *bi_private; /* bio结构体创建者的私有方法 */
#if defined(CONFIG_BLK_DEV_INTEGRITY)
struct bio_integrity_payload *bi_integrity; /* data integrity */
#endif
bio_destructor_t *bi_destructor; /* bio撤销方法 */
/*
* We can inline a number of vecs at the end of the bio, to avoid
* double allocations for a small number of bio_vecs. This member
* MUST obviously be kept at the very end of the bio.
* 内嵌在结构体末尾的 bio 向量,主要为了防止出现二次申请少量的 bio_vecs
*/
struct bio_vec bi_inline_vecs[0]
}
如果申请做下面的处理:struct bio *buf;
int bio_vec_len /*缓冲区数据的长度*/
/*直接把buffer的结构体跟存放数据的内存一起分配了*/
buf = (struct bio *) malloc(sizeof(struct bio) + bio_ven_len*sizeof(struct bio_vec));
buf->bio_vec = "数据struct bio_vec data\n";
/*也可以下面这样引用:*/
buf->bio_vec = “初始化数据”; /*bio_vec data的取值范围:0~bio_vec_len-1*/
在结构体中,我们定义了0长度的数组,按理buf->bio_vec =“初始化数据”;属于越界访问,但是我们把结构体后面的n*sizeof(struct bio_vec)个长度的空间也一起申请了,所以该访问是合法的!
结构体最后使用0或1的长度数组的原因,主要是为了方便的管理内存缓冲区,如果你直接使用指针而不使用数组,那么,你在分配内存缓冲区时,就必须分配结构体一次,然后再分配结构体内的指针一次,(而此时分配的内存已经与结构体的内存不连续了,所以要分别管理即申请和释放)而如果使用数组,那么只需要一次就可以全部分配出来,(见下面的例子),反过来,释放时也是一样,使用数组,一次释放,使用指针,得先释放结构体内的指针,再释放结构体。还不能颠倒次序。
其实就是分配一段连续的的内存,减少内存的碎片化。
example:
在Linux系统里,/usr/include/linux/if_pppox.h里面有这样一个结构:
struct pppoe_tag {
__u16 tag_type;
__u16 tag_len;
char tag_data[0];
} __attribute ((packed));
最后一个成员为可变长的数组,对于TLV(Type-Length-Value)形式的结构,或者其他需要变长度的结构体,用这种方式定义最好。使用起来非常方便,创建时,malloc一段结构体大小加上可变长数据长度的空间给它,可变长部分可按数组的方式访问,释放时,直接把整个结构体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)
更多详细网址: http://*.com/questions/11733981/what-is-the-purpose-of-a-zero-length-array-in-a-struct
https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html