2012-04-23 26 views
7

Tôi muốn sử dụng nftw để duyệt qua cấu trúc thư mục trong C.Cách tránh sử dụng biến toàn cục khi sử dụng nftw

Tuy nhiên, với những gì tôi muốn làm, tôi không thấy cách sử dụng biến toàn cầu.

Ví dụ về sách giáo khoa sử dụng (n) ftw đều liên quan đến việc thực hiện một việc gì đó như in ra tên tệp. Thay vào đó, tôi muốn lấy tên đường dẫn và kiểm tra tệp và đặt chúng trong cấu trúc dữ liệu. Nhưng tôi không thấy một cách tốt để làm điều đó, đưa ra những giới hạn về những gì có thể được thông qua để nftw.

Giải pháp tôi đang sử dụng liên quan đến biến toàn cục. Hàm được gọi bởi nftw sau đó có thể truy cập biến đó và thêm dữ liệu cần thiết.

Có cách nào hợp lý để thực hiện việc này mà không sử dụng biến toàn cầu không?

Here's the exchange in previous post on stackoverflow in which someone suggested I post this as a follow-up.

Trả lời

2

số nftw không cung cấp bất kỳ tham số người dùng có thể được truyền cho hàm, vì vậy bạn phải sử dụng các biến toàn cầu (hoặc tĩnh) trong C.

GCC cung cấp một phần mở rộng " hàm lồng nhau" mà nên nắm bắt các biến của phạm vi bao quanh họ, do đó họ có thể được sử dụng như thế này:

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

số liệu được đưa ra tốt nhất liên kết tĩnh (tức là file-phạm vi) trong một mô-đun riêng biệt mà chỉ bao gồm f yêu cầu truy cập để truy cập dữ liệu, bao gồm cả chức năng được chuyển đến nftw(). Bằng cách đó, dữ liệu không hiển thị trên toàn cầu và tất cả quyền truy cập được kiểm soát. Có thể hàm ntfw() cũng là một phần của mô-đun này, cho phép hàm được truyền tới nftw() cũng là tĩnh và do đó ẩn bên ngoài.

Nói cách khác, bạn nên làm những gì bạn có thể đang làm, nhưng sử dụng trình biên dịch riêng biệt và liên kết tĩnh một cách thận trọng để làm cho dữ liệu chỉ hiển thị qua các chức năng truy cập. Dữ liệu có liên kết tĩnh có thể truy cập bởi bất kỳ chức năng nào trong cùng một đơn vị dịch và bạn tránh các vấn đề liên quan đến biến toàn cầu bằng cách chỉ bao gồm các hàm trong đơn vị dịch đó là người tạo, người duy trì hoặc người truy cập dữ liệu đó.

Các mô hình chung là:

datamodule.h

#if defined DATAMODULE_INCLUDE 
<type> create_data(<args>) ; 
<type> get_data(<args>) ; 
#endif 

datamodule.c

#include "datamodule.h" 

static <type> my_data ; 

static int nftwfunc(const char *filename, const struct stat *statptr, int fileflags, struct FTW *pfwt) 
{ 
    // update/add to my_data 
    ... 
} 


<type> create_data(const char* path, <other args>) 
{ 
    ... 

    ret = nftw(path, nftwfunc, fd_limit, flags); 

    ... 
} 

<type> get_data(<args>) 
{ 
    // Get requested data from my_data and return it to caller 
} 
+0

Tôi nhận thức được giá trị của việc tách biệt mã, vì thư viện BSD "libarchive" (mà tôi cũng đang sử dụng) được thiết lập theo cách đó. Nhưng nhận xét của bạn đã giúp củng cố vấn đề và tôi sẽ sử dụng từ khóa tĩnh hơn một cách tổng quát. (Sẽ upvote bạn nếu tôi có thể.) – user1071847

+1

Bài viết [Pox on globals] (http://www.eetimes.com/discussion/break-point/4025723/A-pox-on-globals) Tôi đã liên kết trong bài đăng trước đó của bạn cũng thảo luận về kỹ thuật này. Bài viết đề cập đến các hệ thống nhúng, nhưng nó không ít được áp dụng cho máy tính mục đích chung. Tôi cũng đề nghị rằng C++ cung cấp cho bạn thêm cơ hội cho việc đóng gói dữ liệu tốt hơn bằng cách sử dụng các lớp và các không gian tên. Một số thận trọng về việc sử dụng tĩnh theo cách này, nó là tốt nếu bạn chỉ cần một ví dụ của dữ liệu, và nó kết quả trong mã không reentrant và không an toàn thread. Các giải pháp khác có thể áp dụng. – Clifford

1

Sử dụng ftw có thể được thực sự, thực sự xấu. Bên trong nó sẽ lưu con trỏ hàm mà bạn sử dụng, nếu một luồng khác sau đó thực hiện một cái gì đó khác nó sẽ ghi đè lên con trỏ hàm.

kịch bản kinh dị:

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. 

Nói tóm lại. Bạn nên sử dụng fts_open.

Nếu bạn vẫn muốn sử dụng nftw thì đề xuất của tôi là đặt loại "toàn cầu" vào một không gian tên và đánh dấu nó là "thread_local".Bạn sẽ có thể điều chỉnh điều này theo nhu cầu của mình.

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

Việc triển khai ftw của glibc lưu con trỏ hàm trên ngăn xếp, chứ không phải trong một biến toàn cầu, do đó, kịch bản kinh dị mà bạn liệt kê là không thể. Điều đó nói rằng, tôi nghĩ rằng đề xuất của bạn sử dụng thread_local là câu trả lời tốt nhất cho câu hỏi này. –

+0

... nhưng fts ít phổ biến hơn ftw. – fche

Các vấn đề liên quan