2013-03-15 19 views
6

Tôi đang viết thư viện C (dùng chung). Nó bắt đầu như một đơn vị dịch thuật duy nhất, trong đó tôi có thể xác định một vài biến số toàn cầu, bị ẩn khỏi các mô-đun bên ngoài.Làm thế nào để ẩn một biến toàn cầu, có thể nhìn thấy trên nhiều tập tin?

Bây giờ thư viện đã phát triển, tôi muốn chia mô-đun thành một vài tệp nguồn nhỏ hơn. Vấn đề là bây giờ tôi có hai lựa chọn cho globals đề cập:

  1. Có bản tin tại mỗi file nguồn và bằng cách nào đó đồng bộ hóa các giá trị của họ thông qua chức năng cuộc gọi - điều này sẽ trở nên rất xấu xí rất nhanh.

  2. Xóa định nghĩa static, do đó, các biến được chia sẻ trên tất cả các đơn vị dịch sử dụng extern - nhưng bây giờ mã ứng dụng được liên kết với thư viện có thể truy cập vào các hình cầu này.

Vì vậy, có cách gọn gàng để biến biến toàn cầu riêng tư được chia sẻ trên nhiều đơn vị dịch thuật cụ thể không?

Trả lời

6

Bạn muốn tiện ích mở rộng visibility attribute của GCC.

Thực tế, một cái gì đó như:

#define MODULE_VISIBILITY __attribute__ ((visibility ("hidden"))) 
#define PUBLIC_VISIBILITY __attribute__ ((visibility ("default"))) 

(Bạn có thể muốn #ifdef macro trên, sử dụng một số thủ thuật cấu hình à la autoconfkhác autotools; trên các hệ thống khác mà bạn sẽ chỉ có định nghĩa rỗng như #define PUBLIC_VISIBILITY /*empty*/ vv ...)

Sau đó, khai báo một biến:

int module_var MODULE_VISIBILITY; 

hoặc một hàm

void module_function (int) MODULE_VISIBILITY; 

Sau đó, bạn có thể sử dụng module_var hoặc gọi module_function bên trong thư viện chia sẻ của bạn, nhưng không phải bên ngoài.

Xem thêm tùy chọn tạo mã -fvisibility của GCC.

BTW, bạn cũng có thể biên dịch toàn bộ thư viện của mình với -Dsomeglobal=alongname3419a6 và sử dụng someglobal như bình thường; để thực sự tìm thấy nó, người dùng của bạn sẽ cần phải chuyển cùng một định nghĩa tiền xử lý cho trình biên dịch và bạn có thể đặt tên alongname3419a6 ngẫu nhiên và không đủ khả năng để làm cho va chạm không thể xảy ra.


PS. Khả năng hiển thị này là cụ thể đối với GCC (và có thể là đối với thư viện được chia sẻ ELF chẳng hạn như trên Linux). Nó sẽ không hoạt động nếu không có GCC hoặc bên ngoài các thư viện được chia sẻ .... vì vậy là khá cụ thể cho Linux (ngay cả khi một số hệ thống khác, có lẽ Solaris với GCC, có nó). Có thể một số trình biên dịch khác (clang từ LLVM) cũng có thể hỗ trợ trên Linux cho thư viện được chia sẻ (không phải là thư mục tĩnh).Trên thực tế, ẩn thực (đối với một số đơn vị biên dịch của một thư viện được chia sẻ) được thực hiện chủ yếu bởi trình liên kết (vì các thư viện chia sẻ ELF cho phép điều đó).

+1

Điều gì khiến bạn nghĩ rằng OP đang sử dụng GCC và tính di động mã đó không được mong muốn? – Lundin

+5

Tôi đã nói đó là một phần mở rộng GCC. Tôi đã thêm một PS lặp đi lặp lại đó. –

+0

Có bạn đã làm. Tôi nhận xét kể từ khi tôi không nghĩ rằng Stack tràn nên là một diễn đàn GCC, tất cả mọi người dường như ngầm giả sử GCC ngày nay. – Lundin

4

Giải pháp dễ nhất ("trường học cũ") đơn giản là không khai báo biến trong tiêu đề công khai dự định.

Tách tiêu đề thư viện của bạn thành "header.h" và "header-internal.h" và khai báo nội dung trong phần sau.

Tất nhiên, bạn cũng nên cẩn thận để bảo vệ tên biến toàn cục của thư viện của mình để không va chạm với mã người dùng; có lẽ bạn đã có một tiền tố mà bạn sử dụng cho các chức năng cho mục đích này.

Bạn cũng có thể quấn (các) biến số trong một struct, để làm cho nó sạch hơn kể từ đó chỉ có một biểu tượng thực tế có thể nhìn thấy trên toàn cầu.

+2

"Bạn có thể bảo vệ mã từ Murphy, nhưng không bao giờ từ Machiavelli." – aschepler

+0

Cảm ơn. Chắc chắn bạn không nên đặt nó trong tệp tiêu đề công khai, nhưng, như tôi đã đề cập trong câu hỏi của tôi, bạn vẫn có thể truy cập biến với khai báo thích hợp trong ứng dụng của bạn. Tôi cố gắng giữ tên biến rõ ràng và súc tích, do đó xác suất của người dùng xác định tên tương tự, đặc biệt. trong ngữ cảnh sử dụng thư viện đó, có phần cao hơn 0. Đây là lý do tại sao tôi đang tìm cách bảo vệ nó. Đặt chúng trong một 'struct', mặc dù, là một ý tưởng tôi có thể sử dụng để tiếp tục giảm xác suất này. – ysap

+0

@ysap Nếu bạn liên kết toàn bộ thư viện của mình thành "thứ gì đó", đó không phải là mã nguồn thô, tất cả các vấn đề không gian tên đó sẽ biến mất và người dùng thư viện của bạn sẽ chỉ phải lo lắng về tiêu đề công khai. – Lundin

2

Bạn có thể làm xáo trộn mọi thứ bằng cấu trúc ngụy trang, nếu bạn thực sự muốn ẩn thông tin tốt nhất có thể. ví dụ. trong một tập tin tiêu đề,

struct data_s { 
    void *v; 
}; 

Và đâu đó trong nguồn của bạn:

struct data_s data; 
struct gbs { 
    // declare all your globals here 
} gbss; 

và sau đó:

data.v = &gbss;

Sau đó bạn có thể truy cập vào tất cả các globals qua: ((struct gbs *)data.v)->

+0

Cảm ơn. Về cơ bản những gì @unwind đề xuất. Obfuscating là giải pháp chuyển tiếp thẳng, nhưng làm cho mã của tôi xấu hơn. – ysap

+0

@ysap Bạn có thể sử dụng các macro để làm cho nó trông đẹp hơn một chút. Nó làm cho mọi việc trở nên khó khăn hơn, nhưng sẽ khó hơn nhiều để tìm ra các biến toàn cầu. – teppic

0

Tôi biết rằng điều này sẽ không phải là những gì bạn biết y dự định, nhưng bạn có thể để biến toàn cục tĩnh và chia chúng thành nhiều tệp nguồn.

Sao chép các chức năng ghi vào biến tĩnh tương ứng trong cùng một tệp nguồn cũng được khai báo là tĩnh.

Khai báo các hàm đọc biến tĩnh để các tệp nguồn bên ngoài của cùng một mô-đun có thể đọc giá trị của nó.

Theo cách làm cho nó ít toàn cầu hơn. Nếu có thể, logic tốt nhất để chia nhỏ các tệp lớn thành các tệp nhỏ hơn, là đưa ra quyết định dựa trên dữ liệu.

Nếu không thể thực hiện theo cách này, bạn có thể gộp tất cả các biến toàn cục thành một tệp nguồn dưới dạng tĩnh và truy cập chúng từ các tệp nguồn khác của mô đun theo chức năng. biến toàn cầu của bạn ít nhất bạn biết làm thế nào. Nhưng sau đó nó có thể là tốt hơn để sử dụng phương pháp @ thư giãn.

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