1

Мне нужно использовать readdir_r(), чтобы прочитать содержимое каталога в многопоточной программе. Поскольку размер struct dirent является файловая система зависит, man readdir_r рекомендуетВыделение структуры dirent без malloc()

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' в соответствии с вашим ответом, а затем определить' обугленного буфер [Len] '. – alk

+0

@alk: 'char buffer [len]' не обязательно правильно выровнен для 'struct dirent'. Кроме того, разыменование объекта типа 'char' с помощью указателя типа' struct dirent' является неопределенным поведением в соответствии с C. – EOF

+0

Вы это «*, но оно нарушает строгую сглаживание»? Выполняется для 'char'-array? – 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' набрано' символ [256] '. – alk

+0

Я приглашаю вас прочитать 'man readdir_r'. – EOF

Смежные вопросы