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

我想要这样一个结构体，其中有的成员可能数目有多个（个数会变化）。如何定义这样一个结构体及如何使用中动态分配内存呢？

1

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

0
@中山野鬼 求教~
0

```#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;
}```

99标准用 char p[]吧，0长度数组标准不支持，只是gcc的扩展，有些编译器不支持这个扩展。gcc用-pedantic会有警告的。
0
```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];

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

0

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

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