零长度数组的妙用

这个零长度数组,基本上在应用开发的时候,很少接触到,今天却遇上了,原因是要使用一个同事开发的内核模块。编译的时候,出现了。

其报错的结构体大概是这样的:

gcc编译的时候,没有给通过。原因是因为加了参数 -pedantic 从上面的 -Werror=pedantic 也可以看出是该错误的原因了。-pedantic 参数的话,简单的说,就是严格遵循ISO C 和 ISO C++的标准。也就是关闭了所有的GNU的扩展了。那么我们就可以说这个零长度的数组是GNU的扩展了。把编译的参数 -pedantic去掉后,确实可以通过。

然后就开始谷歌搜一通吧。看看这个零长度数组,到底有什么用途,因为我也没做内核的开发,从同事的言语中,得知,linux内核代码中,有大量的这种方式的代码。查到了GCC手册。里面说得很详细:

6.17 Arrays of Length Zero

手册是英文的,如果觉得蛋疼,可以看看一个是繁体的翻译,不过是在blogger上的博文,需要爬墙:

C Struct Hack – Structure with variable length array

手册中提供了下面这样的一个结构体:

说的是,打算contents在末尾刚好指向this_length存储的数据空间头,这样就方便我们对于this_length数据的读取操作了。其实就是灵活的运用的数组指向的是其后面的连续的内存空间,但是在C90之前,并不支持0长度的数组,所以C Struct Hack用的方法就是

但是这样显然会浪费空间,sizeof会返回8的长度(内存对齐)。所以GNU就对其进行了扩展。当使用contents[0]的时候,也就是0长度数组的时候,此次返回的长度就为4了。在C99之后,也加了类似的扩展,只不过用的是char payload[]这种形式(所以如果你在编译的时候确实需要用到-pedantic参数,那么你可以将char payload[0]类型改成char payload[],这样就可以编译通过了,当然你的编译器必须支持C99标准的,如果太古老的编译器,那可能不支持了)。所以结构体的末尾,就是指向了其后面的内存数据。因此我们可以很好的将该类型的结构体作为数据报文的头格式,并且最后一个成员变量,也就刚好是负载或内容了。

手册还提供了另外两个结构体来说明,更容易看懂意思:

我把f2里面的2,3,4改成了5,6,7以示区分。如果你把数据打出来。即如下的信息:

f1.x = 1

f1.y[0] = 2

f1.y[1] = 3

f1.y[2] = 4

也就是f1.y指向的是{2,3,4}这块内存中的数据。所以我们就可以轻易的得到,f2.f1.y指向的数据也就是正好f2.data的内容了。打印出来的数据:

f2.f1.x = 1

f2.f1.y[0] = 5

f2.f1.y[1] = 6

f2.f1.y[2] = 7

如果你不是很确认其是否占用空间。你可以用sizeof来计算一下。就可以知道sizeof(struct f1)=4,也就是int y[]其实是不占用空间的。但是这个0长度的数组,必须放在结构体的末尾。如果你没有把它放在末尾的话。编译的时候,会有如下的错误:

到这边,你可能会有疑问,如果将struct f1中的int y[]替换成int *y,又会是如何?这就涉及到数组和指针的问题了。有时候吧,这两个是一样的,有时候又有区别。

首先要说明的是,支持0长度数组的扩展,重点在数组,也就是不能用int *y指针来替换。sizeof的长度就不一样了。把struct f1改成这样:

在64位下,sizeof(struct f1)=4,而sizeof(struct f3)=16。因为int *y是指针,指针在64位下,是64位的,如果在32位环境的话,sizeof(struct f3)则是8了,sizeof(struct f1)不变。所以int *y是不能替代int y[]的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值