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

时间:2015-05-09 10:09:06

标签: c memory-management memory-alignment readdir strict-aliasing

我需要使用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(),它返回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时,有没有办法避免手动内存管理?

2 个答案:

答案 0 :(得分:2)

如何定义:

#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. */
};

答案 1 :(得分:0)

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);