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

相關問題