Hầu hết thời gian trong lập trình C có vẻ như sẽ có một tệp tiêu đề (.h
) cho mỗi tệp mã (.c
), đối với các mẫu thử chức năng ít nhất.Khi nào tệp .c không có tệp .h được liên kết?
Khi nào thì không phù hợp để không có tệp tiêu đề cho tệp mã?
Hầu hết thời gian trong lập trình C có vẻ như sẽ có một tệp tiêu đề (.h
) cho mỗi tệp mã (.c
), đối với các mẫu thử chức năng ít nhất.Khi nào tệp .c không có tệp .h được liên kết?
Khi nào thì không phù hợp để không có tệp tiêu đề cho tệp mã?
Có một vài trường hợp sử dụng cho việc này. Rõ ràng nhất là chương trình chính của bạn hiếm khi cần một tệp tiêu đề.
Thứ hai là nơi bạn không có một tiêu đề cho mỗi tệp C. Tôi đã đặt cùng thư viện trước (giả sử một thư viện BTree cho các mục đích của câu trả lời này), nơi từng chức năng riêng biệt là trong tập tin nguồn riêng của mình nhưng có một tập tin tiêu đề thư viện rộng, một cái gì đó như:
btree.h
btree_priv.h
btreeInit.c
btreeDestroy.c
btreeConfig.c
và Sớm. Tệp tiêu đề riêng tư dành cho nội dung cần được chia sẻ giữa mã nhưng không được xuất bản trong API.
rõ ràng nhất khi .c
hoàn toàn khép kín và không cần phải có mẫu thử hoặc extern cho các tệp .c
khác. điều này về cơ bản là chỉ cho các chương trình rất nhỏ, hoặc những người xuất khẩu thông qua một tập tin def để cắm vào một giao diện được xác định trước.
Trong trường hợp, khi bạn không cần khai báo từ tệp .h
, nhưng điều đó không bao giờ thực sự hiệu quả.
Khi tệp .c chứa dữ liệu không cần sử dụng bởi bất kỳ mã nào.
Phải thừa nhận rằng điều này hiếm - nhưng điều đó có thể xảy ra. Ví dụ tôi đã làm điều này trong các thiết bị nhúng, để cư trú bộ đệm khung hình video với đồ họa khởi động.
Nếu bạn chia chương trình của mình thành một số mô-đun, thường sẽ có mô-đun "chính", chứa hàm main() và có thể một số nội dung khác. Nếu mô-đun này không có bất kỳ thứ gì được cho là được gọi hoặc được sử dụng bởi một mô-đun khác, bạn không cần phải xuất giao diện trong tệp .h.
Tôi đã thấy các cơ sở mã lớn nơi một tệp .h
xác định giao diện cho một số thành phần và một số tệp .c
triển khai nó. Việc triển khai được chia thành nhiều tệp hoàn toàn vì lý do bảo trì và đã được thử ở một số giới hạn hợp lý.
Người ta có thể cho rằng ràng buộc logic có thể được áp dụng để chia thành phần phụ và do đó có nhiều tệp tiêu đề, nhưng các quyết định thiết kế hiếm khi là màu đen & vụ màu trắng và đôi khi cách tiếp cận này có ý nghĩa.
Thông thường, tôi sẽ tạo tệp tiêu đề cho 'chính' ngay cả khi tôi không mong đợi mã khác phải truy cập, vì thường xuyên (1) bản dựng gỡ lỗi sẽ yêu cầu thứ gì đó bên ngoài mô-đun chính để truy cập vào thứ gì đó bên trong nó, hoặc (2) module chính sẽ bị phân chia do các giới hạn trình biên dịch (hệ thống nhúng). Mẫu có mọi tệp .c bao gồm tệp .h của riêng nó đủ mạnh để tôi thường tạo các tệp .h trống gần như ngay cả đối với tệp .c xác định những thứ không được tham chiếu trong mã (chẳng hạn như các bảng nhảy ngắt , v.v.)
Quy ước đặt tên trở nên phức tạp hơn một chút khi tệp bao gồm nhiều tệp do chương trình tạo hoặc bao gồm các tệp cần được biên dịch nhiều lần (ví dụ:một trong các dự án của tôi có hai động cơ, có mã giống hệt nhau ngoại trừ việc chúng sử dụng các cổng I/O khác nhau và các biến khác nhau; tập tin motor.c tôi bao gồm:
#define LOCK L0 #include "motor.i" #undef LOCK #define LOCK L1 #include "motor.i" #under LOCK
Lưu ý rằng trên trình biên dịch được bổ sung này, các -> điều hành là rất không hiệu quả, do đó, một tuyên bố như:
L0.speed++;
sẽ biên dịch sang một hướng dẫn, trong khi một tuyên bố như:
L0->speed++;
sẽ dịch thành năm hướng dẫn nếu 'tốc độ' là mục đầu tiên trong cấu trúc hoặc bảy nếu nó chiếm bất kỳ vị trí nào khác. Do đó, nó hiệu quả hơn về tốc độ và hiệu quả về mặt không gian hơn, để nhân bản mã với các địa chỉ có thể phân giải liên tục hơn là có một xử lý thông thường cả hai động cơ.
Nếu có một tệp phụ được liên kết với tệp .c và tệp đó chứa mã thực, tôi sẽ đặt tên là ".i". Bạn không chắc chắn nên làm gì nếu có nhiều hơn một.
Tôi nghĩ rằng việc mong đợi ánh xạ 1-1 giữa các tệp .c và .h là giả định khởi đầu không tốt. Ném nó ra và bắt đầu tươi. : D
Nhìn vào câu hỏi của bạn theo cách khác, bạn có thể hỏi "Khi nào thích hợp để tạo tệp tiêu đề?"
tôi sẽ gợi ý những điều sau đây, trường hợp thời hạn "mã mô-đun" là một nhóm (thường là một thư mục) của một hoặc liên quan nhiều file .c:
Đó là các tệp tiêu đề duy nhất bạn cần. Nếu không có yêu cầu nào trong số đó là bắt buộc thì bạn không cần tiêu đề.
Một số lập trình viên muốn tạo các mẫu/macro/typedefs/etc riêng biệt giả tạo thành một .h tách biệt với các globals/functions trong .c của chúng. Tôi khuyên bạn nên chống lại phương pháp này và đề xuất có tất cả các chức năng liên quan trong một tệp. Sau đó di chuyển đến các tiêu đề như là cần thiết những điều đó là hoàn toàn cần thiết để ngăn chặn 'extern's trong các tập tin .c khác.
Vì vậy, tôi đoán một hệ quả của câu trả lời này là mô hình mặt tiền thường dẫn đến mối quan hệ .c với mối quan hệ. – Tommy