【问题标题】:Can someone explain this definition of the 'dirent' struct in Solaris?有人可以解释 Solaris 中“dirent”结构的定义吗?
【发布时间】:2010-10-08 11:05:37
【问题描述】:

最近我在看“dirent”结构(在 dirent.h 中),对它的定义有点困惑。

注意:这个头文件来自我学校的一台 Solaris 机器。


typedef struct dirent {
    ino_t       d_ino;
    off_t       d_off;
    unsigned short  d_reclen;
    char        d_name[1];
} dirent_t;

尤其是 d_name 字段。这将如何在操作系统中工作?如果您需要存储一个以空结尾的字符串,那么单个字符的数组有什么用?我知道您可以通过数组的第一个元素获取数组的地址,但我仍然感到困惑。显然发生了什么事,但我不知道是什么。在我家里的 Fedora Linux 系统上,这个字段被简单地定义为:

char d_name[256];

由于显而易见的原因,现在这更有意义了。有人能解释一下为什么 Solaris 头文件会这样定义结构吗?

【问题讨论】:

    标签: c unix struct solaris


    【解决方案1】:

    正如其他人指出的那样,结构的最后一个成员没有任何设置大小。然而,该数组很长,实现决定它需要容纳它想要放入其中的字符。它通过为结构动态分配内存来实现这一点,例如使用malloc

    不过,将成员声明为大小为 1 很方便,因为很容易确定任何 dirent 变量 d 占用了多少内存:

    sizeof(dirent) + strlen(d.d_name)
    

    使用大小 1 也会阻止此类结构值的接收者尝试在其中存储自己的名称,而不是分配自己的 dirent 值。使用 Linux 定义,可以合理地假设您拥有的任何 dirent 值都将接受 255 个字符的字符串,但 Solaris 不保证其 dirent 值将存储比所需更多的字符。

    我认为是 C 99 为结构的最后一个成员引入了一种特殊情况。结构体可以这样声明:

    typedef struct dirent {
      ino_t d_ino;
      off_t d_off;
      unsigned short d_reclen;
      char d_name[];
    } dirent_t;
    

    数组没有声明的大小。这称为灵活数组成员。它完成了与 Solaris 版本相同的事情,除了结构本身可以包含 any 名称这一点没有错觉。你看它就知道它还有更多。

    使用“灵活”声明,占用的内存量将调整如下:

    sizeof(dirent) + strlen(d.d_name) + 1
    

    这是因为灵活的数组成员不考虑结构的大小。

    您没有经常看到这样的灵活声明的原因,尤其是在 OS 库代码中,可能是为了与不支持该功能的旧编译器兼容。这也是为了与针对当前定义编写的代码兼容,如果结构的大小发生这样的变化,这将破坏。

    【讨论】:

    • 其实d_reclen这个入口就是这个struct实例的真实大小,不用自己计算。
    • 啊,你是对的。不过,分配结构的人仍然需要弄清楚要分配多少,所以有一种简单的方法来计算它仍然很好。
    • 在为我的爱好操作系统实现自己的 ext2 驱动程序时,我又回到了这个问题。对我来说,关键是我使用这种结构的方式。我从磁盘读取目录条目,然后将缓冲区转换为dirent_t。然后,灵活的数组成员对应于文件名字符。然后只需阅读以 d.name 开头的 name_len 字符即可。它实际上在实践中效果很好。您可能需要了解如何使用 rec_len 才能了解它的意义。
    【解决方案2】:

    dirent struct 将立即在内存中跟随一个包含名称其余部分的内存块,并且可以通过 d_name 字段访问该内存。

    【讨论】:

      【解决方案3】:

      这是在 C 中用于指示结构末尾的任意长度数组的模式。 C 中的数组没有内置的边界检查,因此当您的代码尝试访问从 d_name 开始的字符串时,它将继续超过结构的末尾。这依赖于readdir() 将分配足够的内存来容纳整个字符串加上终止的 nul。

      【讨论】:

      • 为什么不在结构中使用指针呢?节省几个字节?我想在操作系统级别可能就是这种情况。
      • 指针不做同样的事情。使用指针需要多次内存分配——一个用于 dirent 结构,一个用于名称,而 dirent 指向名称。使用单字节数组模式意味着一次分配,d_name 是名称的第一个字节。
      • 知道了。感谢您的澄清,我没有考虑需要额外的分配。
      【解决方案4】:

      对我来说,它看起来像是一个微优化。名称通常很短,所以为什么要分配您知道将不会使用的空间。此外,Solaris 可能支持超过 255 个字符的名称。要使用这样的结构,您只需分配所需的空间并忽略 supposed 数组大小。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-01-06
        • 2015-03-30
        • 2021-10-14
        • 1970-01-01
        • 2010-09-19
        • 1970-01-01
        • 1970-01-01
        • 2012-05-29
        相关资源
        最近更新 更多