在没有 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. */
};
我需要使用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. */
};