结构体最后的长度为0或1数组的作用(二)

2014-11-24 11:58:38 · 作者: · 浏览: 1
ppoe_tag *)malloc(sizeof(struct pppoe_tag));
sample_tag->tag_len = sample_tag_len;
sample_tag->tag_data = http://www.cnblogs.com/winkyao/archive/2012/02/14/malloc(sizeof(char)*sample_tag_len);
sample_tag->tag_data[0]=...
释放时:
free(sample_tag->tag_data);
free(sample_tag);

方法二:
sample_tag = (struct pppoe_tag *)malloc(sizeof(struct pppoe_tag)+sizeof(char)*sample_tag_len);
sample_tag->tag_len = sample_tag_len;
sample_tag->tag_data = http://www.cnblogs.com/winkyao/archive/2012/02/14/((char *)sample_tag)+sizeof(struct pppoe_tag);
sample_tag->tag_data[0]=...
释放时:
free(sample_tag);
所以无论使用那种方法,都没有char tag_data[0]这样的定义来得方便。
讲了这么多,其实本质上涉及到的是一个C语言里面的数组和指针的区别问题(也就是我们提到的内存管理问题,数组分配的是在结构体空间地址后一段连续的空间,而指针是在一个随机的空间分配的一段连续空间)。char a[1]里面的a和char *b的b相同吗?《Programming Abstractions in C》(Roberts, E. S.,机械工业出版社,2004.6)82页里面说:“arr is defined to be identical to &arr[0]”。也就是说,char a[1]里面的a实际是一个常量,等于&a[0]。而char *b是有一个实实在在的指针变量b存在。所以,a=b是不允许的,而b=a是允许的。两种变量都支持下标式的访问,那么对于a[0]和b[0]本质上是否有区别?我们可以通过一个例子来说明。
例二:
10 #include
20 #include
30
40 int main()
50 {
60 char a[10];
70 char *b;
80
90 a[2]=0xfe;
100 b[2]=0xfe;
110 exit(0);
120 }

编译后,用objdump可以看到它的汇编:
080483f0
:
80483f0: 55 push %ebp
80483f1: 89 e5 mov %esp,%ebp
80483f3: 83 ec 18 sub $0x18,%esp
80483f6: c6 45 f6 fe movb $0xfe,0xfffffff6(%ebp)
80483fa: 8b 45 f0 mov 0xfffffff0(%ebp),%eax
80483fd: 83 c0 02 add $0x2,%eax
8048400: c6 00 fe movb $0xfe,(%eax)
8048403: 83 c4 f4 add $0xfffffff4,%esp
8048406: 6a 00 push $0x0
8048408: e8 f3 fe ff ff call 8048300 <_init+0x68>
804840d: 83 c4 10 add $0x10,%esp
8048410: c9 leave
8048411: c3 ret
8048412: 8d b4 26 00 00 00 00 lea 0x0(%esi,1),%esi
8048419: 8d bc 27 00 00 00 00 lea 0x0(%edi,1),%edi

可以看出,a[2]=0xfe是直接寻址,直接将0xfe写入&a[0]+2的地址,而b[2]=0xfe是间接寻址,先将b的内容(地址)拿出来,加2,再0xfe写入计算出来的地址。所以a[0]和b[0]本质上是不同的。
但当数组作为参数时,和指针就没有区别了。
int do1(char a[],int len);
int do2(char *a,int len);
这两个函数中的a并无任何区别。都是实实在在存在的指针变量。
顺便再说一下,对于struct pppoe_tag的最后一个成员的定义是char tag_data[0],某些编译器不支持长度为0的数组的定义,在这种情况下,只能将它定义成char tag_data[1],使用方法相同。
在openoffice的源代码中看到如下数据结构,是一个unicode字符串结构,他的最后就用长度为1数组,可能是为了兼容或者跨编译器。

typedef struct _rtl_uString
{
sal_Int32 refCount;
sal_Int32 length;
sal_Unicode buffer[1];
} rtl_uString;
这是不定长字符串。大概意思是这样:

rtl_uString * str = malloc(256);
str->length = 256;
str->buffer现在就指向一个长度为256 - 8的缓冲区



总结:通过上面的转载的文章,可以清晰的发现,这种方法的优势其实就是为了简化内存的管理,我们假设在理想的内存状态下,那么分配的内存空间,可以是按序下来的(当然,实际因为内存碎片等的原因会不同的)我们可以利用最后一个数组的指针直接无间隔的跳到分配的数组缓冲区,这在LINUX下非常常见,在WINDOWS下的我只是在MFC里见过类似的,别的情况下记不清楚了,只记得MFC里的是这么讲的,可以用分配的结构体的指针(this)直接+1(详细的方法请看我的博客:CE分类里的:内存池技术的应用和详细说明),就跳到实际的内存空间,当初也是想了半天,所以说,很多东西看似很复杂,其实都是基础的东西,要好好打实基础,这才是万丈高楼拔地巍峨的前提和保障,学习亦是如是,切忌好高骛远,应该脚踏实地,一步一步的向前走,而且要不时的总结自己的心得和体会,理论和实践不断的相互印证,才能够走得更远,看到更美丽的风景。
最后,再次感谢网上无私共享的童鞋们!!!



柔性数组结构成员收藏【柔性数组结构成员
  C99中,结构中的最后一个元素允许是未知大小的数组,这就叫做柔性数组成员,但结构中的柔性数组成员前面必须至少一个其他成员。柔性数组成员允许结构中包含一个大小可变的数组。sizeof返回的这种结构大小不包括柔性数组的内存。包含柔性数组成员的结构用malloc ()函数进行内存的动态分配,并且分配的内存应该大于结构的大小,以适应柔性数组的预期大小。】
C语言大全,“柔性数组成员”

【柔性数组结构成员
  C99中,结构中的最后一个元素允许是未知大小的数组,这就叫做柔性数组成员,但结构中的柔性数组成员前面必须至少一个其他成员。柔性数组成员允许结构中包含一个大小可变的数组。sizeof返回的这种结构大小不包括柔性数组的内存。包含柔性数组成员的结构用malloc ()函数进行内存的动态分配,并且分配的内存应该大于结构的大小,以适应柔性数组的预期大小。】
C语言大全,“柔性数组成员”

看看C99 标准中灵活数组