2011-12-18 12 views
5

Tôi có một mã được biên dịch thành một thư viện (dll, thư viện tĩnh và như vậy). Tôi muốn người dùng của thư viện này sử dụng một số cấu trúc để truyền một số dữ liệu làm tham số cho hàm thư viện. Tôi đã nghĩ về việc khai báo cấu trúc trong tệp tiêu đề API.Định nghĩa cấu trúc trong tệp tiêu đề cho thư viện và các khác biệt biên dịch

  • Có an toàn không khi xem xét việc biên dịch với các trình biên dịch khác nhau, liên quan đến sắp xếp cấu trúc hoặc những thứ khác mà tôi không nghĩ đến?
  • Nó có yêu cầu sử dụng cùng một trình biên dịch (và cờ) cho cả thư viện và người dùng của nó không?

vài lưu ý:

  1. tôi coi cho người sử dụng một con trỏ và đặt tất cả các cấu trúc thông qua chức năng trong thư viện, nhưng điều này sẽ làm cho các API thực sự không thoải mái khi sử dụng.
  2. Câu hỏi này là về C, mặc dù sẽ thật tuyệt nếu biết có sự khác biệt trong C++.

Trả lời

2

Nếu thư viện thông thường/tĩnh, thư viện và ứng dụng phải được biên dịch bằng cùng một trình biên dịch. Có một vài lý do cho điều này mà tôi có thể nghĩ đến:

  1. Trình biên dịch khác nhau (như trong các thương hiệu hoặc trình biên dịch khác nhau) thường không hiểu định dạng thư viện và đối tượng của nhau.
  2. Bạn không muốn biên dịch các phần khác nhau của cùng một chương trình bằng cách sử dụng các loại khác nhau (ví dụ: ký kết hoặc unsigned char), loại kích cỡ (ví dụ: dài = 32 so với 64 bit), căn chỉnh và đóng gói và một số thứ khác được phép theo tiêu chuẩn C thay đổi. Trộn và kết hợp những thứ đó thường là một điều xấu.

Bạn có thể, tuy nhiên, thường sử dụng các phiên bản hơi khác nhau của cùng một trình biên dịch để biên dịch thư viện và ứng dụng sử dụng nó. Thông thường, không sao. Đôi khi có những thay đổi phá vỡ mã, mặc dù.

Bạn có thể thực hiện một số chức năng "khởi tạo" trong tệp tiêu đề (được khai báo là static inline) để đảm bảo rằng loại, loại kích cỡ, căn chỉnh và đóng gói giống như mong đợi của thư viện được biên dịch. Ứng dụng sử dụng thư viện này sẽ phải gọi hàm này trước khi sử dụng bất kỳ phần nào khác của thư viện. Nếu mọi thứ không giống như mong đợi, chức năng phải thất bại và gây ra sự chấm dứt chương trình, có thể với một số mô tả văn bản tốt về sự thất bại. Điều này sẽ không giải quyết hoàn toàn vấn đề của việc có phần mềm biên dịch không tương thích, nhưng nó có thể ngăn chặn sự cố im lặng và bí ẩn. Một số điều có thể được kiểm tra bằng chỉ thị trước của #if#ifdef và gây ra lỗi biên dịch với #error.

Ngoài ra, các vấn đề về cấu trúc đóng gói có thể được giảm bớt bằng cách chèn byte đệm rõ ràng vào khai báo cấu trúc và buộc đóng gói chặt chẽ (ví dụ:sử dụng #pragma pack, được hỗ trợ bởi nhiều trình biên dịch). Bằng cách đó, nếu kích thước loại giống nhau, nó sẽ không quan trọng những gì đóng gói mặc định là.

Bạn có thể áp dụng tương tự cho các tệp DLL, nhưng bạn thực sự mong rằng ứng dụng gọi đã được biên dịch bằng trình biên dịch khác và không phụ thuộc vào trình biên dịch giống nhau.

+0

Cảm ơn câu trả lời chi tiết. Bạn đã cho tôi một số điều mới để suy nghĩ. – MByD

0

Tất cả các API Windows đều ném cấu trúc xung quanh như điên, vì vậy rõ ràng đây là thứ được thực hiện hàng ngày và hoạt động. Tất nhiên điều đó không có nghĩa là các mối quan tâm của bạn không hợp lệ :) Tôi khuyên bạn nên tạo các trường của cấu trúc của bạn có các loại chiều rộng rõ ràng (int32_t etc) và có thể chỉ định rõ ràng rằng đóng gói theo cách sẽ phá vỡ bất kỳ trình biên dịch nào , tức là

#if defined(_MSC_VER) 
#pragma pack(0) 
#elif defined ... handle gcc 
#else 
FAIL // fail compilation on unsupported platform 
#endif 
+0

API Windows * chắc chắn * xác định đóng gói rõ ràng cho cấu trúc của chúng. Họ chỉ đóng gói/làm xáo trộn tất cả trong tiêu đề. Bạn đang * có thể * an toàn làm điều này, nhưng tập thể dục chăm sóc được khuyến khích triệt để. –

+0

gcc hỗ trợ gói #pragma. –

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