在没有 malloc() 的情况下分配结构 dirent

Allocating a struct dirent without malloc()

我需要使用readdir_r()在多线程程序中读取目录的内容。由于 struct dirent 的大小取决于文件系统,man readdir_r 建议

name_max = pathconf(dirpath, _PC_NAME_MAX);
if (name_max == -1)                     /* Limit not defined, or error */
    name_max = 255;                     /* Take a guess */
len = offsetof(struct dirent, d_name) + name_max + 1;

找到所需分配的大小。分配它

entryp = malloc(len);

被调用,最后readdir_r()这样使用:

struct dirent *returned;
readdir_r(DIR*, entryp, &returned);

但是,我想避免调用 malloc()(或任何其他手动内存管理函数)。

我想到的一种方法是

_Alignas(struct dirent) char direntbuf[len];
struct dirent *entryp = (struct dirent*) direntbuf;

这应该提供正确对齐的分配,但它违反了严格的别名。但是,缓冲区永远不会通过 char* 访问,因此最可能的问题,即编译器通过不同类型重新排序对缓冲区的访问,不会发生。

另一种方法是 alloca(),returns 和 void*,避免了严格的别名问题。但是,alloca() 似乎不能像 malloc() 和朋友那样保证对齐。要始终获得对齐的缓冲区,例如

void *alloc = alloca(len + _Alignof(struct dirent));
struct dirent *direntbuf = (struct dirent*)((uintptr_t)&((char*)alloc)[_Alignof(struct dirent)]&-_Alignof(struct dirent));

需要。特别是,需要转换为 char * 才能对指针执行算术运算,而需要转换为 uintptr_t 才能执行二进制 &。这看起来并不比分配 char[].

更明确

有没有办法在分配 struct dirent 时避免手动内存管理?

readdir_r 函数签名是:

int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result);

direct 是这样的结构:

struct dirent {
    ino_t          d_ino;       /* inode number */
    off_t          d_off;       /* offset to the next dirent */
    unsigned short d_reclen;    /* length of this record */
    unsigned char  d_type;      /* type of file; not supported
                                   by all file system types */
    char           d_name[256]; /* filename */
};

您必须传递一个指向 readdir_r 的指针,但是如何为 dirent 结构分配内存完全取决于您。

您可以这样做并使用堆栈变量。

struct dirent entry = {0};
...
readdir_r(DIR*, &entry, &returned);

定义这个怎么样:

#include <stddef.h> /* For offsetof */
#include <dirent.h>


union U
{
  struct dirent de;
  char c[offsetof(struct dirent, d_name) + NAME_MAX + 1]; /* NAME_MAX is POSIX. */
};