Allocating a struct dirent without malloc()

折月煮酒 提交于 2020-12-12 11:38:47

问题


I need to use readdir_r() to read the contents of a directory in a multithreaded program. Since the size of struct dirent is filesystem dependent, man readdir_r recommends

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;

to find the size of the allocation needed. To allocate it

entryp = malloc(len);

is called, and finally readdir_r() uses it like this:

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

However, I'd like to avoid calling malloc() (or any other manual memory management function).

One way I've thought of is

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

This should give a correctly aligned allocation, but it violates strict aliasing. However, the buffer is never accessed via a char* so the most likely problem, the compiler reordering accesses to the buffer via different types, cannot occur.

Another way could be by alloca(), which returns a void*, avoiding strict aliasing problems. However, alloca() does not seem to guarantee alignment the way malloc() and friends do. To always get an aligned buffer, something like

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

would be needed. In particular, the cast to char * is needed to perform arithmetic on a pointer, and the cast to uintptr_t is needed to do the binary &. This doesn't look more well-defined than allocating a char[].

Is there a way to avoid manual memory management when allocating a struct dirent?


回答1:


What about defining this:

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



回答2:


The readdir_r function signature is:

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

And direct is a struct like this:

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

You have to pass a pointer to readdir_r but how you allocate memory for the dirent structure is entirely up to you.

You could do it like this and use a stack variable.

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


来源:https://stackoverflow.com/questions/30138626/allocating-a-struct-dirent-without-malloc

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!