我在Linux环境中使用C编程语言来读取目录中的文件.我已经包含#include
在我的代码中并使用了该函数readdir()
.
根据Linux在线页面,它说不会调用free()
结果指针到dirent
结构,因为它可能被分配在堆栈上.
你能帮我理解它是如何工作的吗?我不明白为什么我们不必删除struct dirent
.什么时候删除谁删除它?
以下是我所说的摘录:
成功时,
readdir()
返回指向dirent
结构的指针.(此结构可以静态分配;不要尝试free(3)
它.)如果到达目录流的末尾,NULL
则返回并且errno
不会更改.如果发生错误,NULL
则返回并errno
适当设置.
cadaniluk.. 10
man readdir
字面上说:
成功时,
readdir()
返回指向dirent结构的指针.(此结构可以静态分配;不要尝试free(3)
.)
(代码格式化程序已添加.)
这意味着它的空间不是在运行时分配的,例如堆栈或空闲存储内存,而是static
:它在可执行文件本身,与字符串文字相比,区别在于写入字符串文字是未定义的行为.
想象一下实现是这样的:
struct dirent *readdir(DIR *dirp) { static struct dirent dir; /* Fill dir with appropriate values. */ return &dir; }
dir
在这里静态分配.返回它的地址没有错,因为它存在于程序的整个运行时间中.
这是readdir
我的glibc 2.22实现的实际源代码(路径是/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->data
是static
数据.
这是什么原因,为什么有折返替代readdir_r
和readdir
是不可重入.
想象一下两个线程同时执行readdir
.两者都会尝试同时填充dir
(在所有readdir
调用之间共享),导致无序的内存读/写.
man readdir
字面上说:
成功时,
readdir()
返回指向dirent结构的指针.(此结构可以静态分配;不要尝试free(3)
.)
(代码格式化程序已添加.)
这意味着它的空间不是在运行时分配的,例如堆栈或空闲存储内存,而是static
:它在可执行文件本身,与字符串文字相比,区别在于写入字符串文字是未定义的行为.
想象一下实现是这样的:
struct dirent *readdir(DIR *dirp) { static struct dirent dir; /* Fill dir with appropriate values. */ return &dir; }
dir
在这里静态分配.返回它的地址没有错,因为它存在于程序的整个运行时间中.
这是readdir
我的glibc 2.22实现的实际源代码(路径是/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->data
是static
数据.
这是什么原因,为什么有折返替代readdir_r
和readdir
是不可重入.
想象一下两个线程同时执行readdir
.两者都会尝试同时填充dir
(在所有readdir
调用之间共享),导致无序的内存读/写.