在标准C和C++中0长数组如charArray[0]是不容许使用的,由于这从语义逻辑上看,是彻底没有意义的。数组
可是,GUN中却容许使用,并且,不少时候,应用在了变长结构体中,如:网络
StructPacketsocket
{spa
Int state;.net
Int len;指针
Char cData[0]; //这里的0长结构体就为变长结构体提供了很是好的支持blog
};内存
首先对0长数组作一个解释:编译器
用途 :长度为0的数组的主要用途是为了知足须要变长度的结构体。编译
用法 :在一个结构体的最后 ,申明一个长度为0的数组,就可使得这个结构体是可变长的。对于编译器来讲,此时长度为0的数组并不占用空间,由于数组名自己不占空间,它只是一个偏移量, 数组名这个符号自己代 表了一个不可修改的地址常量 (注意:数组名永远都不会是指针! ),但对于这个数组的大小,咱们能够进行动态分配
请仔细理解后半部分,对于编译器而言,数组名仅仅是一个符号,它不会占用任何空间,它在结构体中,只是表明了一个偏移量,表明一个不可修改的地址常量!
对于0长数组的这个特色,很容易构造出变成结构体,如缓冲区,数据包等等:
Struct Buffer
{
Int len;
Char cData[0];
};
这样的变长数组经常使用于网络通讯中构造不定长数据包,不会浪费空间浪费网络流量,好比我要发送1024字节的数据,若是用定长包,假设定长包的长度为2048,就会浪费1024个字节的空间,也会形成没必要要的流量浪费
Struct packet
{
char data[2048];
}
packet p;
memcpy(p.data,"1024 datas.........",1024)
send(socket,(char*)&p,sizeof(p));
因为考虑到数据的溢出,变长数据包中的data数组长度通常会设置得足够长足以容纳最大的数据,所以packet中的data数组不少状况下都没有填满数据,所以形成了浪费,而若是咱们用变长数组来进行封包的话,就不会形成浪费(最多会形成4个字节的浪费,包头的int型的len不属于数据所以算是浪费),如前面的Buffer结构体,假如咱们要发送1024个字节,咱们如何构造这个数据包呢:
char *tmp = (char*)malloc(sizeof(Buffer)+1024) //这句代码的做用是申请一块连续的内存空间,这块内存空间的长度是Buffer的大小加上1024数据的大小,由两部分构成,sizeof(Buffer)和1024,若是仔细观察的话,会发现这种申请方法比第一种多了一段sizeof(Buffer)大小的空间,缘由何在?以下
Buffer *p = (Buffer*)tmp;
p->len = 1024;
memcpy(p.cData,"1024 datas............",1024);
如上三行代码,首先作一个强制类型转换,Buffer类型的指针指向内存的起始位置,这段内存要分两部分使用,前部分4个字节p->len,做为包头(就是多出来的那部分),这个包头是用来描述紧接着包头后面的数据部分的长度,这里是1024,因此前四个字节赋值为1024(既然咱们要构造不定长数据包,那么这个包到底有多长呢,所以,咱们就必须经过一个变量来代表这个数据包的长度,这就是len的做用),而紧接其后的内存是真正的数据部分,经过p->cData定位到该部分的起始地址,最后,进行一个memcpy()内存拷贝,把要发送的数据填入到这段内存当中,最后:
send(socket,p,sizeof(Buffer)+1024);发送数据
转自:http://blog.csdn.net/yby4769250/article/details/7294696