1

我需要使用readdir_r()来读取多线程程序中目录的内容。由于struct dirent的大小依赖于文件系统,man readdir_r建议在没有malloc的情况下分配struct dirent()

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时有没有办法避免手动内存管理?

+0

对于<= C99:计算'len'按您的回答,然后定义'字符缓冲区[长度]'。 – alk

+0

@alk:'char buffer [len]'不一定为'struct dirent'正确对齐。另外,根据C. – EOF

+0

,通过类型为“struct dirent”的指针取消引用类型为“char”的对象是未定义的行为。对于char类型数组,您是“*但它违反严格别名*”吗? – alk

回答

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

哇,这实际上非常聪明......我对这种联盟的使用印象深刻。 – EOF

+0

好吧,我会咬。为什么联合而不是结构? – usr2564301

+0

@jongware:结构如何在这里帮助? – alk

0

的readdir_r函数签名是:

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

和直接的是这样一个结构:

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

这是不可移植的,因为只有在Linux'd_name'键入'char [256]'。 – alk

+0

我邀请你阅读'man readdir_r'。 – EOF

相关问题