我在Linux环境中使用C编程语言来读取目录中的文件.我包括#include< dirent.h>在我的代码中,我正在使用函数readdir().
根据Linux在线页面,它说不会在结果指向dirent结构的地方调用free(),因为它可能被分配在堆栈上.
你能帮我理解它是如何工作的吗?我不明白为什么我们不必删除struct dirent.什么时候删除谁删除它?
Here是我所说的摘录:
On success,
readdir()
returns a pointer to adirent
structure. (This structure may be statically allocated; do not attempt tofree(3)
it.) If the end of the directory stream is reached,NULL
is returned anderrno
is not changed. If an error occurs,NULL
is returned anderrno
is set appropriately.
On success,
readdir()
returns a pointer to a dirent structure.
(This structure may be statically allocated; do not attempt to
free(3)
it.)
这意味着它的空间不是在运行时分配的,例如堆栈或空闲存储内存,而是静态的:它在可执行文件本身,与字符串文字相当,区别在于写入字符串文字是未定义的行为.
想象一下实现是这样的:
struct dirent *readdir(DIR *dirp) {
static struct dirent dir;
/* Fill dir with appropriate values. */
return &dir;
}
dir在这里静态分配.返回它的地址没有错,因为它存在于程序的整个运行时间中.
这是我的glibc 2.22实现上readdir的实际源代码(路径为/sysdeps/posix/readdir.c):
DIRENT_TYPE *
__READDIR (DIR *dirp)
{
DIRENT_TYPE *dp;
int saved_errno = errno;
#if IS_IN (libc)
__libc_lock_lock (dirp->lock);
#endif
do
{
size_t reclen;
if (dirp->offset >= dirp->size)
{
/* We've emptied out our buffer. Refill it. */
size_t maxread;
ssize_t bytes;
#ifndef _DIRENT_HAVE_D_RECLEN
/* Fixed-size struct; must read one at a time (see below). */
maxread = sizeof *dp;
#else
maxread = dirp->allocation;
#endif
bytes = __GETDENTS (dirp->fd,dirp->data,maxread);
if (bytes <= 0)
{
/* On some systems getdents fails with ENOENT when the
open directory has been rmdir'd already. POSIX.1
requires that we treat this condition like normal EOF. */
if (bytes < 0 && errno == ENOENT)
bytes = 0;
/* Don't modifiy errno when reaching EOF. */
if (bytes == 0)
__set_errno (saved_errno);
dp = NULL;
break;
}
dirp->size = (size_t) bytes;
/* Reset the offset into the buffer. */
dirp->offset = 0;
}
dp = (DIRENT_TYPE *) &dirp->data[dirp->offset];
#ifdef _DIRENT_HAVE_D_RECLEN
reclen = dp->d_reclen;
#else
/* The only version of `struct dirent*' that lacks `d_reclen'
is fixed-size. */
assert (sizeof dp->d_name > 1);
reclen = sizeof *dp;
/* The name is not terminated if it is the largest possible size.
Clobber the following byte to ensure proper null termination. We
read jst one entry at a time above so we know that byte will not
be used later. */
dp->d_name[sizeof dp->d_name] = '\0';
#endif
dirp->offset += reclen;
#ifdef _DIRENT_HAVE_D_OFF
dirp->filepos = dp->d_off;
#else
dirp->filepos += reclen;
#endif
/* Skip deleted files. */
} while (dp->d_ino == 0);
#if IS_IN (libc)
__libc_lock_unlock (dirp->lock);
#endif
return dp;
}
我不太了解glibc但是线路
dp = (DIRENT_TYPE *) &dirp->data[dirp->offset];
对我们来说似乎是最有趣的. dirp->数据就是这里的静态数据,据我所知.
这就是为什么有可重入的替代readdir_r和readdir不可重入的原因.
想象两个线程同时执行readdir.两者都会尝试同时填充所有readdir调用之间共享的dir,导致无序的内存读/写.