分配不带malloc()的结构目录

分配不带malloc()的结构目录,c,memory-management,memory-alignment,readdir,strict-aliasing,C,Memory Management,Memory Alignment,Readdir,Strict Aliasing,我需要使用readdir\u r()读取多线程程序中目录的内容。由于struct dirent的大小取决于文件系统,因此man readdir\u r建议 name_max = pathconf(dirpath, _PC_NAME_MAX); if (name_max == -1) /* Limit not defined, or error */ name_max = 255; /* Take a gues

我需要使用
readdir\u r()
读取多线程程序中目录的内容。由于
struct dirent
的大小取决于文件系统,因此
man readdir\u 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\u r()
如下使用它:

struct dirent *returned;
readdir_r(DIR*, entryp, &returned);
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 */
};
但是,我希望避免调用
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*
,而对
uintpttr\t
的转换则需要执行二进制
。这看起来并不比分配一个
char[]
更明确


在分配
结构目录时,是否有避免手动内存管理的方法?

readdir函数签名为:

int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result);
direct是这样的结构:

struct dirent *returned;
readdir_r(DIR*, entryp, &returned);
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. */
};
#包括/*用于抵消*/
#包括
联合大学
{
结构设计;
字符c[offsetof(struct dirent,d_name)+name_MAX+1];/*name_MAX是POSIX*/
};

这是不可移植的,因为只有在Linux上,
d\u name
才是键入的
char[256]
。对于@alk:
char buffer[len]
而言,它不一定正确对齐
结构目录。此外,根据C,通过
struct dirent
类型的指针取消对
char
类型的对象的引用是未定义的行为。您是否认为
char
-array“但它违反了严格的别名”适用。C11草案标准第6.5节规定,只能通过指向对象类型的指针或字符类型的指针访问对象。但是如果对象已经是一个
字符
,这在这里没有帮助。啊哈,不幸的是,这不适用于另一个方向…:-哇,这实际上非常聪明。。。联合的这种用法给我留下了深刻的印象。@jongware:结构在这里有什么帮助?与您的建议相同,但不需要使用
thingy.Sry的
偏移量,但我不明白您的意思@JongwareJust
struct U2{struct dirent de;char c[NAME_MAX+1];/*NAME_MAX是POSIX.*/}。我不明白你为什么想把它变成一个联盟。