使用nftw时如何避免使用全局变量

我想使用nftw遍历C中的目录结构。

但是,考虑到我想要做的事情,我没有看到使用全局变量的方法。

使用(n)ftw的教科书示例都涉及执行打印文件名等操作。 相反,我希望获取路径名和文件校验和并将它们放在数据结构中。 但考虑到可以传递给nftw的限制,我没有看到一个好方法。

我正在使用的解决方案涉及一个全局变量。 然后,nftw调用的函数可以访问该变量并添加所需的数据。

没有使用全局变量有没有合理的方法呢?

这是在stackoverflow上一篇文章中的交换,有人建议我将其作为后续发布。

nftw不提供任何可以传递给函数的用户参数,因此您必须在C中使用全局(或静态)变量。

GCC提供了一个扩展“嵌套函数”,它应该捕获它们的封闭范围的变量,因此它们可以像这样使用:

 void f() { int i = 0; int fn(const char *, const struct stat *, int, struct FTW *) { i++; return 0; }; nftw("path", fn, 10, 0); } 

使用ftw可能非常非常糟糕 。 在内部,它将保存您使用的函数指针,如果另一个线程然后执行其他操作,它将覆盖函数指针。

恐怖场景:

 thread 1: count billions of files thread 2: delete some files thread 1: ---oops, it is now deleting billions of files instead of counting them. 

简而言之。 你最好使用fts_open。

如果您仍想使用nftw,那么我的建议是将“全局”类型放在命名空间中并将其标记为“thread_local”。 您应该能够根据您的需要进行调整。

 /* in some cpp file */ namespace { thread_local size_t gTotalBytes{0}; // thread local makes this thread safe int GetSize(const char* path, const struct stat* statPtr, int currentFlag, struct FTW* internalFtwUsage) { gTotalBytes+= statPtr->st_size; return 0; //ntfw continues } } // namespace size_t RecursiveFolderDiskUsed(const std::string& startPath) { const int flags = FTW_DEPTH | FTW_MOUNT | FTW_PHYS; const int maxFileDescriptorsToUse = 1024; // or whatever const int result = nftw(startPath.c_str(), GetSize, maxFileDescriptorsToUse , flags); // log or something if result== -1 return gTotalBytes; } 

数据最好在单独的模块中给出静态链接(即文件范围),该模块仅包括访问数据所需的函数,包括传递给nftw()的函数。 这样,数据在全局范围内不可见,并且所有访问都受到控制。 可能是调用ntfw()的函数也是该模块的一部分,使传递给nftw()的函数也是静态的,因此在外部是不可见的。

换句话说,你应该做你可能已经做过的事情,但是明智地使用单独的编译和静态链接来使数据仅通过访问函数可见。 具有静态链接的数据可由同一翻译单元内的任何function访问,并且通过仅包括该翻译单元中作为该数据的创建者,维护者或访问者的function,可以避免与全局变量相关的问题。

一般模式是:

datamodule.h

 #if defined DATAMODULE_INCLUDE  create_data( ) ;  get_data(  ) ; #endif 

datamodule.c

 #include "datamodule.h" static  my_data ; static int nftwfunc(const char *filename, const struct stat *statptr, int fileflags, struct FTW *pfwt) { // update/add to my_data ... }  create_data( const char* path, ) { ... ret = nftw( path, nftwfunc, fd_limit, flags); ... }  get_data(  ) { // Get requested data from my_data and return it to caller }