如何定义不定长结构体,及分配空间

此号作废 发布于 2013/08/27 23:30
阅读 1K+
收藏 0
    我想要这样一个结构体,其中有的成员可能数目有多个(个数会变化)。如何定义这样一个结构体及如何使用中动态分配内存呢?
加载中
1
mallon
mallon

基本思路:

  1. 定义结构体。不定长部分用指针,当然如果能固定最大长度而且不太长的话数组也可以
  2. 定义针对该结构体的分配和释放函数,例如struct xxx * alloc_xxx(参数...),void free_xxx(struct xxx * p)

0
中山野鬼
中山野鬼

贴段代码给你,这个是我自己写的基本库里的代码,看你是否能理解,你注意,p[0] ,和hp的用法,在_setP的宏里有定义,实际申请到的空间,返回的位置会空出一段,给另外个结构体。通过_Pheader的宏,可以访问到。这里先补充几个类型的定义

#define _CONST_UT(_T_,n) typedef const unsigned _T_ _uc##n;
#define _CONST_ST(_T_,n) typedef const signed _T_ _ic##n;
#define _UNSIGNED_T(_T_,n) typedef unsigned _T_ _u##n; _CONST_UT(_T_,n);
#define _SIGNED_T(_T_,n) typedef signed _T_ _i##n; _CONST_ST(_T_,n);
#define _CREATE_T(_T_,n) _UNSIGNED_T(_T_,n) _SIGNED_T(_T_,n)
_CREATE_T(char,8)
//typedef signed char _i8;
//typedef const signed char _ic8;
//typedef unsigned char _u8;
//typedef const unsigned char _uc8;
_CREATE_T(short,16)
_CREATE_T(int,32)
_CREATE_T(long long,64)
typedef _u8 * _p;//byte point

typedef _u32 _I;// memory space size  & index

typedef _u64 _PI;// the point type 2 interger type , i386 need typedef _u32 _PI;


#define _p2I(p)	(_PI)(p) //get p address change to interger..
typedef struct {
	//_i64 pheader[0];
	_p hp;//header base p;
	_I ns;// ns * us == s
	_I t;//tail not used
	_I h;//head not used
	_I n;// data unit num
	_I us; // unit size
	_I s;//size
	_u8 p[0];//have bug if used BUS_S a[10];;so not allow used array mode
}_D_BUF;
typedef _D_BUF * _P;

#define _SIZE(Q) (Q)->s
#define _HEAD(Q) (Q)->h
#define _TAIL(Q) (Q)->t
#define _NUM(Q) (Q)->n
#define _UNITS(Q) (Q)->us
#define _UNIT_NUM(Q) (Q)->ns
#define _sizeP(hs,s)  (_salign8(hs) +  _salign8(s) + _salign8(sizeof(_D_BUF)))

#define _initP(P,ns,us) do {_bug(ns == 0);\
 _UNITS(P) = ((us) == 0)? 1 : (us);\
 _UNIT_NUM(P) = ns;\
 _SIZE(P) = _UNIT_NUM(P) * _UNITS(P);  _HEAD(P) = 0; _TAIL(P) = 0;\
_NUM(P) = 0;\
}while (0)
//op to _P
#define _Pheader(P,_T_) ((_T_*)((P)->hp))

#define _setP(P,_ph,header_size,unit_num,unit_s) do {\
	P = (_P)(_ph+header_size); \
	_initP(P,unit_num,unit_s);\
	(P)->hp = (_p)(_ph);\
} while (0) //init all 


static _P m_alloc(_I ns,_I hs,_I us,_cs usr,_cs maker){
	
	_I s = ns * us;
	_P pre = 0;
	_p p;
	_error(check_alloc_tab((_p)0) == ss_alloc->buf_size,c_m_alloc_EXIT,
		"%s maker:%s :usr:%s ",error_str[ERR_ALLOC_OVERFLOW],maker,usr);
	_bug(s == 0);
	p = (_p)malloc(_sizeP(hs,s));//sizeof(_D_BUF)+s + hs);
	
	_bug(_p2I(p) & 0x7);
	ss_alloc->alloc_buf[ss_alloc->buf_bias].p = p;
	ss_alloc->alloc_buf[ss_alloc->buf_bias].maker = maker;
	ss_alloc->alloc_buf[ss_alloc->buf_bias].usr = usr;	

	_setP(pre,p,hs,ns,us);

c_m_alloc_EXIT:
	return pre;
}
此号作废
此号作废
谢谢~^_^
中山野鬼
中山野鬼
回复 @gvim : 你说的这个情况我重新看了标准,确实如此。不过暂时不动。哈。
gvim
gvim
99标准用 char p[]吧,0长度数组标准不支持,只是gcc的扩展,有些编译器不支持这个扩展。gcc用-pedantic会有警告的。
0
gvim
gvim
struct cd {
    int ab;
    char a[];
};

int main()
{
    struct cd *cd;
    cd = (struct cd *)malloc(sizeof(struct cd) + 1024);
    cd->ab = 2;
    cd->a[0] = 'a';
    cd->a[1] = 'b';

    return 0;
}

@Mallon 指针 和  char[] 的差别一是需要多一个域来放指针,二是char[]只是符号,因此分配出来的内存和头部是连续的,而指针的分配是一个和头部不连续地址的。第二种情况在计算校验的时候很方便,不管头部怎么设计怎么变,只要把这段地址做为连续内存遍历即可,或者做数据包的时候。

此号作废
此号作废
谢谢~
0
中山野鬼
中山野鬼

@gvim ,你说的char p[0],c的iso标准不支持是对的。如果使用 char p[]会存在问题,它需要放在结构体的下部。当我需要在结构体下面扩充成员时,会产生问题。曾经用过p[]的写法。最终还是决定使用char p[0];

我刚才翻了一下我以前的intel c编译器,还没测试过,奶奶的过期了。。对我来说,支持这两个编译器就足够了。哈。

不过我要看我的基础库做完后的情况,如果这个基础结构体下部,可以不增加其他成员,我会采用p[],毕竟如你说的,这样适用面更宽。哈。

0
乌龟壳
乌龟壳

这个技巧我觉得可以称作结构体的单一继承

//纯手写,可能有错,看下大概意思就好了

struct base {
    char name[5];
    int age;
    double weight;
};

struct emploee {
    struct base;
    int level;
    char department[100];
};

int get_age_x_weight(struct base *b)
{
    return b->age * b->weight;
}

int get_level_x_age_x_weight(struct emploee *e)
{
    //(struct base*)e可以将它转化成它的父结构体的形态
    //这样就能使用父结构体的操作了
    //对于父结构体,struct emploee就是它的一种扩充
    //这个技巧在许多地方都可以用,可以不改变系统接口的同时,
    //夹带私有数据,简化实现,提高性能(不用涉及到运行时的查找算法)
    return e->level * get_age_x_weight((struct base*)e);
}
0
gvim
gvim

引用来自“中山野鬼”的答案

@gvim ,你说的char p[0],c的iso标准不支持是对的。如果使用 char p[]会存在问题,它需要放在结构体的下部。当我需要在结构体下面扩充成员时,会产生问题。曾经用过p[]的写法。最终还是决定使用char p[0];

我刚才翻了一下我以前的intel c编译器,还没测试过,奶奶的过期了。。对我来说,支持这两个编译器就足够了。哈。

不过我要看我的基础库做完后的情况,如果这个基础结构体下部,可以不增加其他成员,我会采用p[],毕竟如你说的,这样适用面更宽。哈。

可变长结构体你怎么在下面扩充固定成员?就算真在尾巴后面扩充了成员,它们相对首元素的偏移还能固定吗?就如同我只见过可变长参数必须是函数参数列表的最后一个一样,我也只能理解可变长结构体最后一个域的动态性。so,如果不是我见识少就是你太天真。

0
中山野鬼
中山野鬼

引用来自“gvim”的答案

引用来自“中山野鬼”的答案

@gvim ,你说的char p[0],c的iso标准不支持是对的。如果使用 char p[]会存在问题,它需要放在结构体的下部。当我需要在结构体下面扩充成员时,会产生问题。曾经用过p[]的写法。最终还是决定使用char p[0];

我刚才翻了一下我以前的intel c编译器,还没测试过,奶奶的过期了。。对我来说,支持这两个编译器就足够了。哈。

不过我要看我的基础库做完后的情况,如果这个基础结构体下部,可以不增加其他成员,我会采用p[],毕竟如你说的,这样适用面更宽。哈。

可变长结构体你怎么在下面扩充固定成员?就算真在尾巴后面扩充了成员,它们相对首元素的偏移还能固定吗?就如同我只见过可变长参数必须是函数参数列表的最后一个一样,我也只能理解可变长结构体最后一个域的动态性。so,如果不是我见识少就是你太天真。

哈,如果我下面有成员,就不会对p[]采用动态分配,甚至不用它。有些时候,p[]带空间,有些时候不带空间。
返回顶部
顶部