最近我在查看'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头文件定义结构吗?
答案 0 :(得分:10)
正如其他人所指出的,结构的最后一个成员没有任何设置大小。然而,数组很长,实现决定它需要容纳它想要放入其中的字符。它通过动态分配结构的内存来实现,例如使用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版本相同的功能,除了没有错觉结构本身可以包含任何名称。你知道它还有更多内容。
使用“灵活”声明,占用的内存量将如下调整:
sizeof(dirent) + strlen(d.d_name) + 1
这是因为灵活的数组成员不会考虑结构的大小。
您没有经常看到这种灵活声明的原因,特别是在OS库代码中,可能是为了与不支持该工具的旧编译器兼容。它也是为了与目标定义编写的代码的兼容性,如果结构的大小改变那么会破坏。
答案 1 :(得分:5)
dirent结构将在内存中立即跟随包含名称其余部分的内存块,并且该内存可通过d_name字段访问。
答案 2 :(得分:5)
这是C中用于表示结构末尾的任意长度数组的模式。 C中的数组没有内置边界检查,因此当您的代码尝试访问从d_name开始的字符串时,它将继续超过结构的末尾。这取决于readdir()
将分配足够的内存来保存整个字符串加上终止的nul。
答案 3 :(得分:1)
对我来说,这似乎是一种微观优化。名称通常很短,所以为什么要分配你知道不会使用的空间。此外,Solaris可能支持超过255个字符的名称。要使用这样的结构,您只需分配所需的空间并忽略假定的数组大小。