为什么有些结构体中会定义一个字节的数组
有一些Windows结构体是可变长度的,它们通常会有一个固定长度的头部,然后接下来是一个可变长度的数组。当这些结构体被声明的时候,它们通常会被声明为一个只有一个字节元素的数组,如下图所示:
如果我们观察一下头文件中的定义,就会发现,这里的ANYSIZE_ARRAY被定义成了1,也就是说,这个结构体的结尾是一个只包含1个字节的数组。
通过这样的声明,我们可以分配一个可变长度的结构体,如下图所示:
然后,我们可以通过下图所示的方式来对结构体进行初始化:
有一些开发者可能会认为这个结构体应该像下图这样定义:
然后,结构体的内存分配就看起来像下图这样进行:
这样的做法,会有两个缺陷:一个表面上可见的缺陷,和一个致命缺陷,容我慢慢道来。
首先,这样的设计,会导致客户非常难以访问一个可变长度的数据,对TOKEN_GROUPS结构体的初始化可能如下图这样进行:
真正的缺陷在于,上述代码会在一台64位Windows系统上崩溃,下面是SID_AND_ATTRIBUTES结构体的定义:
上述的结构体定义中,第一个成员是一个PSID指针。SID_AND_ATTRIBUTES结构体需要指针对齐,而在一台64位的Windows系统上是8字节对齐的。另一方面,TOKEN_GROUPS结构仅仅包含一个DWORD,因此它仅需要在4字节边界上对齐,而sizeof(TOKEN_GROUPS)的值为4。
我希望你能看出来现在是什么样一个状况。
从底层结构上来看,SID_AND_ATTRIBUTES结构不会对齐到一个8字节的边界,而是会对齐到4个字节边界,而用来填充这中间的间隙的部分被忽视了。所以,当尝试访问这个数组的成员的时候,会直接导致一个STATUS_DATATYPE_MISALIGNMENT异常。
你可能会问了,那为什么不使用一个长度为0的数组,而使用1个字节的数组呢?
因为:”时间旅行目前还只是一个幻想而已。”
在1999年之前,标准C语言还不支持一个长度为0的数组。而Windows的开发远远早于这个时间点,因而不大可能会利用这个语言特性。
总结
可变长度的数据结构,在网络数据传输中颇有用处。
我为啥知道?兄弟我吃过这方面的亏。
最后
Raymond Chen的《The Old New Thing》是我非常喜欢的博客之一,里面有很多关于Windows的小知识,对于广大Windows平台开发者来说,确实十分有帮助。
本文来自:《Why do some structures end with an array of size 1?》
最近我写了个东西
正如你们所知道的,拓扑梅尔智慧办公平台(Topomel Box)是一款绿色软件,主要面向经常使用电脑的朋友。它提供了各种提升办公效率的小功能,同时操作上尽可能地简单方便。
我想:你值得拥有。
- 下一篇: 关于x86平台上内存对齐的重要性
- 上一篇: 为什么不能将FILETIME看做__int64
相关推荐
- 为什么Windows错误报告叫作”Dr. Watson”?
- Posted on 01月09日
- 实战经验:Ubuntu 16.04 apt-get设置HTTP代理
- Posted on 01月08日
- 致游戏开发者:VS2019对浮点操作的性能改进
- Posted on 03月02日
- 浅谈无效化一个空窗口的后果
- Posted on 07月07日
评论已关闭。