Chinaunix首页 | 论坛 | 博客
  • 博客访问: 341259
  • 博文数量: 56
  • 博客积分: 2058
  • 博客等级: 中尉
  • 技术积分: 688
  • 用 户 组: 普通用户
  • 注册时间: 2011-04-11 09:19
个人简介

code rush

文章分类

全部博文(56)

文章存档

2012年(2)

2011年(54)

分类: LINUX

2011-06-20 10:21:36

零长数组
    在标准 C 或者 C++ 中由于不支持 0 长度的数组,所以 int array[0];
这样的定义是非法的。不过有些编译器(如GCC)的扩展功能支持 0 长度的数组。
    在 C 中,0 长度的数组的主要用途是用来作为结构体的最后一个成员,
然后用它来访问此结构体对象之后的一段内存(通常是动态分配的内存)。
由于其非标准性,在程序中尽量避免使用 0 长度的数组。作为替换,可以
使用 C99 标准中的不完整数组来替换 0 长度的数组定义。如:
        typedef struct _X {
            int a;
            char array[]; //不完整数组,因此不可以计算sizeof(X),无法编译通过
        } X;
    在GNU的gcc-4.4.0的官方指南中的5.14节Arrays of Length Zero一节中,写道:
        struct line {
            int length;
            char contents[0];
        };
        //...ommit code here
        struct line *thisline = (struct line *) malloc (sizeof (struct line) + this_length);
        thisline->length = this_length;
    这个用法主要用于变长Buffer,struct line的大小为4,
结构体中的contents[0]不占用任何空间,甚至是一个指针的空间都不占
(待会儿下面的示例代码会验证),contents在这儿只是表示一个常量指针,
这个特性是用编译器来实现的,即在使用thisline->contents的时候,这个指针
就是表示分配内存地址中的某块buffer,比如malloc (sizeof (struct line) + this_length)
返回的是0x8f00a40,thisline->contents指向的位置就是(0x8f00a40 + sizeof(struct line)),
而这儿sizeof(struct line)仅仅是一个int的四字节。
    对于这个用法,我们定义的结构体指针可以指向任意长度的内存buffer,这个技巧在
变长buffer中使用起来相当方便。为什么不把最后的contents直接定义为一个指针呢?
这儿的差别是这样的,如果定义为一个指针,它需要占用4Bytes,并且在申请好内存后
必须人为赋地址才可以。如果使用这个用法,这个常量指针不占用空间,并且无需赋值。
    但是,方便并不是绝对的,在释放分配的内存的时候,由于函数free会认为*thisline 只是
指向一个4字节的指针,即只会释放length的空间,而对于后面占据大头的buffer却视而不见,
这个就需要人为干预;而对于后面的声明指针的方式,则可以直接用Free(thisline->contents)
的方式释放掉分配的内存。
    如果将零长数组array换成指针*array来使用的话,指针必须重新分配一段内存之后才能使用,
那么当想要用socket发送结构体指针的时候,并不会将指针array申请的内存发送过去,
因为是不连续的,所以接受socket发送来的数据后,会发现该数据并不是自己想要的。
struct t
{
int a;
int arr[0];
};

int main()
{
printf("%d\n",sizeof(struct t));//4, arr[0] 不占用任何空间
}
阅读(3620) | 评论(0) | 转发(2) |
给主人留下些什么吧!~~